From 4f9a983729ec05768f8e541e552b60dfb1f92d82 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Thu, 19 Mar 2026 14:18:13 -0400 Subject: [PATCH 01/87] update_NPT_NP_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 15 ++++++++++++--- src/initialization.c | 13 ++++++++++++- src/readfiles.c | 7 +++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index e1e886d7..06c88d07 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -880,8 +880,12 @@ typedef struct _SPARC_OBJ{ double Hamiltonian_NPT_NH; // Hamiltonian of the NPT-NH system // NPT-NP int maxTimeIter; // largest allowed amount of iteration - double NPT_NP_qmass; // qmass used in NPT_NP - double NPT_NP_bmass; // bmass used in NPT_NP + double pr_external; // Externally applied hydrostatic pressure, used in NPT_NP and NPH + double stress_external[6]; // Externally applied anisotropic stress (applied separately from pr_external), used in NPT_NP and NPH + //In NPT_NP and NPH, the target_stress[i] = pr_external+stress_external[i]; in contrast to NPT_NH where there is just target_pressure. + + double NPT_NP_qmass; // fictitious mass of thermostat (qmass) used in NPT_NP + double NPT_NP_bmass; // fictitious mass of barostat (bmass) used in NPT_NP double range_x_velo; // velocity of x sidelength double range_y_velo; // velocity of y sidelength double range_z_velo; // velocity of z sidelength @@ -1422,7 +1426,12 @@ typedef struct _SPARC_INPUT_OBJ{ // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. double NPT_NHqmass[L_QMASS];// qmass used in NPT_NH double NPT_NHbmass; // Bmass used in NPT_NH - double prtarget; // Target pressure of barostatic system, UNIT on input file is GPa + double prtarget; // Target pressure of NPT_NH system, UNIT on input file is GPa + + double pr_external; // Externally applied hydrostatic pressure of NPT_NP or NPH system, UNIT on input file is GPa + double stress_external[6]; // Externally applied anisotropic stress tensor (applied separately from pr_external) of NPT_NP or NPH system, UNIT on input file is GPa + //In NPT_NP and NPH, the target_stress[i] = pr_external+stress_external[i]; in contrast to NPT_NH where there is just target_pressure. + double NPT_NP_qmass; // qmass used in NPT_NP double NPT_NP_bmass; // Bmass used in NPT_NP diff --git a/src/initialization.c b/src/initialization.c index b6e9edc9..18345b8f 100644 --- a/src/initialization.c +++ b/src/initialization.c @@ -1549,6 +1549,11 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { } pSPARC->NPT_NHbmass = pSPARC_Input->NPT_NHbmass; pSPARC->prtarget = pSPARC_Input->prtarget; + pSPARC->pr_external = pSPARC_Input->pr_external; + for (i = 0; i < 6; i++){ + pSPARC->stress_external[i] = pSPARC_Input->stress_external[i]; + } + pSPARC->pr_external = pSPARC_Input->pr_external; pSPARC->NPT_NP_bmass = pSPARC_Input->NPT_NP_bmass; pSPARC->NPT_NP_qmass = pSPARC_Input->NPT_NP_qmass; pSPARC->NLCG_sigma = pSPARC_Input->NLCG_sigma; @@ -3913,7 +3918,13 @@ void write_output_init(SPARC_OBJ *pSPARC) { else if (pSPARC->NPTconstraintFlag == 4) fprintf(output_fp," 123\n"); fprintf(output_fp,"NPT_NP_QMASS: %.15g\n",pSPARC->NPT_NP_qmass); fprintf(output_fp,"NPT_NP_BMASS: %.15g\n",pSPARC->NPT_NP_bmass); - fprintf(output_fp,"TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget); + fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->pr_external+pSPARC->stress_external[0] + ,pSPARC->pr_external+pSPARC->stress_external[1] + ,pSPARC->pr_external+pSPARC->stress_external[2] + ,pSPARC->stress_external[3] + ,pSPARC->stress_external[4] + ,pSPARC->stress_external[5]); + } } diff --git a/src/readfiles.c b/src/readfiles.c index 67bb969b..6b989d85 100644 --- a/src/readfiles.c +++ b/src/readfiles.c @@ -795,6 +795,13 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } else if (strcmpi(str,"NPT_NP_BMASS:") == 0) { fscanf(input_fp,"%lf",&pSPARC_Input->NPT_NP_bmass); fscanf(input_fp, "%*[^\n]\n"); + }else if (strcmpi(str,"EXTERNAL_PRESSURE:") == 0) { + fscanf(input_fp,"%lf",&pSPARC_Input->pressure_external); + fscanf(input_fp, "%*[^\n]\n"); + }else if (strcmpi(str,"EXTERNAL_STRESS:") == 0) { + fscanf(input_fp,"%lf %lf %lf %lf %lf %lf",&pSPARC_Input->stress_external[0], &pSPARC_Input->stress_external[1], &pSPARC_Input->stress_external[2] + ,&pSPARC_Input->stress_external[3], &pSPARC_Input->stress_external[4], &pSPARC_Input->stress_external[5]); + fscanf(input_fp, "%*[^\n]\n"); } else if (strcmpi(str,"STANDARD_EIGEN:") == 0) { fscanf(input_fp,"%d",&pSPARC_Input->StandardEigenFlag); fscanf(input_fp, "%*[^\n]\n"); From cec8f82663f33fc63462edf7d2e05c8f5e04cdf9 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Thu, 19 Mar 2026 14:25:16 -0400 Subject: [PATCH 02/87] update_NPT_NP_and_add_NPH_full_cell_flexibility added a function to calculate Lattice angles, reciprocal lattice vectors, etc for initial set up in NPT_NP and NPH dynamics --- src/include/md.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/include/md.h b/src/include/md.h index fd7ce831..0c0f5aea 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -157,6 +157,11 @@ void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC); */ void NPT_NP(SPARC_OBJ *pSPARC); +/* +@ brief: Calculates cell angles, reciprocal lattice vectors, metric and reciprocal metric tensors, for use in NPT_NP and NPH dynamics +*/ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC); + /* @ brief: calculate Hamiltonian of the NPT_NP system. */ From 2929194fb63f916dde8ca3e9630058d37d8a9d1b Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Sat, 21 Mar 2026 18:24:47 -0400 Subject: [PATCH 03/87] Update_NPT_NP_and_add_NPH_full_cell_flexibility --- src/md.c | 958 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 852 insertions(+), 106 deletions(-) diff --git a/src/md.c b/src/md.c index fc4e1445..296d6f3f 100644 --- a/src/md.c +++ b/src/md.c @@ -301,8 +301,8 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); Calculate_ionic_stress(pSPARC); } - // Variables for NPT_NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && pSPARC->RestartFlag != 1){ + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -318,44 +318,47 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { exit(EXIT_FAILURE); } } - pSPARC->range_x_velo = 0.0; - pSPARC->G_NPT_NP[0] = pow(pSPARC->range_x, 2.0); - pSPARC->range_y_velo = 0.0; - pSPARC->G_NPT_NP[1] = pow(pSPARC->range_y, 2.0); - pSPARC->range_z_velo = 0.0; - pSPARC->G_NPT_NP[2] = pow(pSPARC->range_z, 2.0); - - pSPARC->scale = 1.0; // better to move to initialization.c - // pSPARC->prtarget = 6.0 // input variable, unit in GPa - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - if(pSPARC->NPT_NP_qmass == 0.0) { + + //Calculate metric_tensor G, reciprocal metric tensor, angles between lattice vectors, rotation matrix + fetch_MD_cell_ingredients(pSPARC); + + pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i1 = 0; i1 < 6; i1++){ + pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ if (!rank) { - printf("Mass of thermostat variable cannot be zero. Please input valid amount of mass of thermo variable.\n"); + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable. Using a zero mass would resemble NPH ensemble, if this is the case then please choose MD_METHOD as NPH \n"); exit(EXIT_FAILURE); } } + + if(strcmpi(pSPARC->MdMeth,"NPH")){ + pSPARC->NPT_NPH_qmass = 0 + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble. If choosing MD_method as NPH with nonzero thermostat mass, it would be automatically set to zero at this point\n"); + } + } - pSPARC->S_NPT_NP = 1.0; - pSPARC->Sv_NPT_NP = 0.0; + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) pSPARC->thermos_Ti = pSPARC->ion_T; pSPARC->thermos_T = pSPARC->thermos_Ti; - if (pSPARC->NPTscaleVecs[0] == 1) - pSPARC->Pm_NPT_NP[0] = pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)/pSPARC->S_NPT_NP*2*pSPARC->range_x*pSPARC->range_x_velo/pSPARC->G_NPT_NP[0]; - else - pSPARC->Pm_NPT_NP[0] = 0.0; - if (pSPARC->NPTscaleVecs[1] == 1) - pSPARC->Pm_NPT_NP[1] = pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)/pSPARC->S_NPT_NP*2*pSPARC->range_y*pSPARC->range_y_velo/pSPARC->G_NPT_NP[1]; - else - pSPARC->Pm_NPT_NP[1] = 0.0; - if (pSPARC->NPTscaleVecs[2] == 1) - pSPARC->Pm_NPT_NP[2] = pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)/pSPARC->S_NPT_NP*2*pSPARC->range_z*pSPARC->range_z_velo/pSPARC->G_NPT_NP[2]; - else - pSPARC->Pm_NPT_NP[2] = 0.0; } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { // restart + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -364,13 +367,29 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); pSPARC->maxTimeIter = 30; - pSPARC->G_NPT_NP[0] = pSPARC->range_x * pSPARC->range_x; - pSPARC->G_NPT_NP[1] = pSPARC->range_y * pSPARC->range_y; - pSPARC->G_NPT_NP[2] = pSPARC->range_z * pSPARC->range_z; + + fetch_MD_cell_ingredients(pSPARC); // pSPARC->thermos_Ti = pSPARC->elec_T; pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i1 = 0; i1 < 6; i1++){ + pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MdMeth,"NPH")){ + pSPARC->NPT_NPH_qmass = 0 + } + Calculate_ionic_stress(pSPARC); } @@ -1334,14 +1353,10 @@ void NPT_NP (SPARC_OBJ *pSPARC) { MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - // calculate Hamiltonian of the NPT_NP system. - initialize_Hamiltonian(pSPARC); - // updating momentums of thermostat and barostat variables and particles in the first half step in NPT_NP. - updateMomentum_FirstHalf(pSPARC); - // updating momentums of thermostat and barostat variables and particles in the second half step in NPT_NP. - updateMomentum_SecondHalf(pSPARC); - // updating value of thermostat variable and length of cell and positions of particles in NPT_NP. - updatePosition(pSPARC); + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell reinitialize_mesh_NPT(pSPARC); @@ -1358,54 +1373,308 @@ void NPT_NP (SPARC_OBJ *pSPARC) { #endif } + +/* +@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant +This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + pSPARC->NPT_NP_qmass = 0; + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1, int flag){ + + //Pure transpose + if (flag==0){ + double tmp; + // Swap (0,1) with (1,0) + tmp = matrix1[1]; matrix1[1] = matrix1[3]; matrix1[3] = tmp; + // Swap (0,2) with (2,0) + tmp = matrix1[2]; matrix1[2] = matrix1[6]; matrix1[6] = tmp; + // Swap (1,2) with (2,1) + tmp = matrix1[5]; matrix1[5] = matrix1[7]; matrix1[7] = tmp; + } + + //performs matrix1 = matrix1 + transpose(matrix1) + else if (flag==1){ + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; + } +} + /* - @ brief: initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix */ -void initialize_Hamiltonian(SPARC_OBJ *pSPARC){ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC){ + + double old_cell[9]; double new_cell[9]; + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row, col; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3]/sqrt(metric_tensor[0]); + new_cell[4] = sqrt(pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3]*pSPARC->metric_tensor[3])/pSPARC->metric_tensor[0]; + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6]/sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = (pSPARC->metric_tensor[0]*pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3]*pSPARC->metric_tensor[6])/sqrt(pSPARC->metric_tensor[0]*pSPARC->metric_tensor[0]*pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0]*pSPARC->metric_tensor[3]*pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]) + + for (int i = 0; i<9; i++){ + old_cell[i] = pSPARC->full_lattice[i] + } + + // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = cblas_ddot(3,&lattice1[3], 1.0, &lattice1[6],1.0 )/(pSPARC->range_y*pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = cblas_ddot(3,&lattice1[0], 1.0, &lattice1[6],1.0 )/(pSPARC->range_x*pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = cblas_ddot(3,&lattice1[0], 1.0, &lattice1[3],1.0 )/(pSPARC->range_x*pSPARC->range_y); // cos_gamma + + // Calculate the inverse of lattice-vector + double U[9], S[3], VT[9], superb[2], temp_mat[9] + double S_inv[9] = {0} + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3,3,old_cell,3,S,U,3,VT,3,superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since lattice1 is rowMajor, reciprocal_lattice1 is columnMajor + // i.e. the reciprocal lattice vectors (of lattice1) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPRAC->reciprocal_lattice, 3); + + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasTrans, CblasTrans, 3, 3, 3, 1.0, pSPRAC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + // Now computing reciprocal metric tensor, + cblas_dgemm(cblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPRAC->reciprocal_lattice, 3, pSPRAC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + + //TODO: Update cell volume + //TODO: Update Jacbdet + //TODO: Update LatVec + //TODO: Update LatUvec + + //Computing velocity of lattice vectors + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int iu1 = 0; iu1 < 9; iu1++){ + temp_mat_3[iu1] = pSPARC->Pm_metric_tensor; + } + + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int iu1 = 0; iu1 < 9; iu1++){ + temp_mat_2[iu1] = 0.0; + pSPARC->lattice_avg_velo[iu1] = 0.0; + } + + temp_mat_2[0] = temp_mat_3[0] / (2.0 * new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->rotation_matrix , 3, temp_mat_2, 3, 0.0, pSPARC->lattice_avg_velo, 3); + +} + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + double vec1[3]; + int count = 0; + + pSPARC->KE = 0.0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + cblas_dgemv(CblasRowMajor, CblasNoTrans,3,3,1.0,pSPARC->reciprocal_metric_tensor,3,&pSPARC->Pm_ion[count*3],1,0.0,vec1,1); + pSPARC->KE += cblas_ddot(3,vec1,1, &pSPARC->Pm_ion[count*3],1)/pSPARC->Mass[ityp]; + count ++; + } + } + pSPARC->KE = 0.5*pSPARC->KE/(pSPARC->SNOSE[0]*pSPARC->SNOSE[0]); + double temperature = 2.0*pSPARC->KE/(pSPARC->dof*pSPARC->kB) +} + + +void Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ + double kinetic_stress[9] = {0.0}; + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count*3] = (pSPARC->reciprocal_metric_tensor[0] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[1] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[2] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count*3+1] = (pSPARC->reciprocal_metric_tensor[3] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[4] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[5] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count*3+2] = (pSPARC->reciprocal_metric_tensor[6] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[7] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[8] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; + + } + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3]; + kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+1]; + kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+2]; + kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+1]; + kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+2]; + count++; + } + } + + kinetic_stress[3] = kinetic_stress[1]; + kinetic_stress[6] = kinetic_stress[2]; + kinetic_stress[7] = kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), kinetic_stress, 1); + + for (int its1 = 0; its1<9; its1++){ + pSPARC->total_internal_stress[its1] = ( kinetic_stress[its1] - pSPARC->internal_stress - pSPARC->constraint_stress) + } + + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); + + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); + +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); double ktemp; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + pSPARC->ionic_forces_fractional = (double *)malloc(pSPARC->n_atom*3 * sizeof(double) ); - if (pSPARC->NPTscaleVecs[0] == 1) - pSPARC->Pm_NPT_NP[0] = pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0) / pSPARC->S_NPT_NP * 2.0 *pSPARC->range_x*pSPARC->range_x_velo / pow(pSPARC->G_NPT_NP[0], 2.0); - else - pSPARC->Pm_NPT_NP[0] = 0; - if (pSPARC->NPTscaleVecs[1] == 1) - pSPARC->Pm_NPT_NP[1] = pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0) / pSPARC->S_NPT_NP * 2.0 *pSPARC->range_y*pSPARC->range_y_velo / pow(pSPARC->G_NPT_NP[1], 2.0); - else - pSPARC->Pm_NPT_NP[1] = 0; - if (pSPARC->NPTscaleVecs[2] == 1) - pSPARC->Pm_NPT_NP[2] = pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0) / pSPARC->S_NPT_NP * 2.0 *pSPARC->range_z*pSPARC->range_z_velo / pow(pSPARC->G_NPT_NP[2], 2.0); - else - pSPARC->Pm_NPT_NP[2] = 0; + //Initialize some useful constants + double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; - pSPARC->KE = 0.0; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10a)----------------------------------// + // Calculating momentum of ions int ityp, atm; int count = 0; + cblas_dscal(pSPARC->n_atom*3,pSPARC->SNOSE[2],pSPARC->ion_vel,1); for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + cblas_dgemv(CblasRowMajor,CblasNoTrans,3,3,pSPARC->Mass[ityp],pSPARC->metric_tensor,3,&pSPARC->ion_vel[count*3],1,0.0,&pSPARC->Pm_ion[count*3],1) count ++; } } - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pow(pSPARC->Sv_NPT_NP, 2.0); - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->S_NPT_NP) * ktemp; - double a[3]; - for (int i = 0; i < 3; i++){ - a[i] = 1.0 / (pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) * pSPARC->Pm_NPT_NP[i] * pSPARC->G_NPT_NP[i]; - } - pSPARC->Kbaro = 0.5 * pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0) * (a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); - pSPARC->Ubaro = pSPARC->prtarget * pSPARC->volumeCell; + // Calculating kinetic energy of ions + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor,1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(pSPARC->n_atom*3,baro_const2,pSPARC->Pm_metric_tensor,1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9,temp_mat_a, 1, temp_mat_b,1);//Kinetic + pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell; //Potential + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5*cblas_ddot(9,pSPARC->external_stress_lattice,1,pSPARC->metric_tensor,1) double sumAllHamilTerms = pSPARC->Etot; sumAllHamilTerms += pSPARC->KE + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; } - pSPARC->Hamiltonian_NPT_NP = pSPARC->S_NPT_NP * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); #ifdef DEBUG if (rank == 0) { printf("\n"); @@ -1421,54 +1690,531 @@ void initialize_Hamiltonian(SPARC_OBJ *pSPARC){ printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); } #endif + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10a)----------------------------------// + + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + ktemp = pSPARC->kB * pSPARC->thermos_T; + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; + pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; + + // Update the kinetic energy of the thermostat + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + } + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress[4] = pSPARC->stress[3]; internal_stress[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress[2] = pSPARC->stress[2]; internal_stress[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress[6] = pSPARC->stress[2]; internal_stress[7] = pSPARC->stress[4]; + + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: so reciprocal lattice vectors are columns) + for (int itma1 = 0; itma1<9; itma1++){ + temp_mat_a[itma1] = pSPARC->reciprocal_lattice[itma1]; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3,pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int ix1 = 0; ix1<9; ix1++){ + temp_Pm_mat[ix1] = pSPARC->Pm_metric_tensor[ix1]; + } + + // Eqn. 18h Hernandez paper + for (int ih18 = 0; ih18<9; ih18++){ + temp_mat[ih18] = internal_stress_fractional[ih18] - pSPARC->kinetic_stress[ih18] + temp_mat_b[ih18]; + temp_mat[ih18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ih18] + 0.5*pSPARC->external_stress_lattice[ih18]; + pSPARC->Pm_metric_tensor[ih18] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ih18]; + } + + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + + for (int ih18 = 0; ih18<9; ih18++){ + temp_mat[ih18] = internal_stress_fractional[ih18] + pSPARC->constraint_stress[ih18] - pSPARC->kinetic_stress[ih18] + temp_mat_b[ih18]; + temp_mat[ih18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ih18] + 0.5*pSPARC->external_stress_lattice[ih18]; + pSPARC->Pm_metric_tensor[ih18] = temp_Pm_mat[ih18] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ih18]; + } + + if (ISIF == 10){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + + if (ISIF == 11){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9,temp_mat_a, 1, temp_mat_b,1);//Kinetic + + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + double thermo_const0 = pSPARC->MD_dt*pSPARC->SNOSE[0] / 2.0; + for(int natm1 = 0; natm1 < pSPARC->n_atom; natm1++){ + pSPARC->ionic_forces_fractional[natm1*3] = (pSPARC->full_lattice[0] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[1] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[2] * pSPARC->forces[natm1*3+2]); + pSPARC->ionic_forces_fractional[natm1*3+1] = (pSPARC->full_lattice[3] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[4] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[5] * pSPARC->forces[natm1*3+2]); + pSPARC->ionic_forces_fractional[natm1*3+2] = (pSPARC->full_lattice[6] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[7] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[8] * pSPARC->forces[natm1*3+2]); + + pSPARC->Pm_ion[natm1*3] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3]; + pSPARC->Pm_ion[natm1*3+1] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+1]; + pSPARC->Pm_ion[natm1*3+2] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+2]; + } + + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + + //Now write Intenal pressure, external pressure to a file + + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + //Calculate/Update total energy (Hamiltonian) + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + double constant_of_motion = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); + //Optionall write all individual energy contributions to the Hamiltonian to an output file + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + for(int natm1 = 0; natm1 < pSPARC->n_atom; natm1++){ + pSPARC->Pm_ion[natm1*3] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3]; + pSPARC->Pm_ion[natm1*3+1] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+1]; + pSPARC->Pm_ion[natm1*3+2] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+2]; + } + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC); + + //Now impose the constraints on it + if (ISIF == 10){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + + if (ISIF == 11){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + double ktemp = pSPARC->kB * pSPARC->thermos_T; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * (log(pSPARC->SNOSE[0])+1) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + if ((1.0 - factor*pSPARC->MD_dt/pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + exit(EXIT_FAILURE); + } + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("Sv_NPT_NP in the 2nd half step is %12.9f\n", pSPARC->Sv_NPT_NP); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new; double S_temp; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT ensemble + S_temp = pSPARC->SNOSE[0]; + + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp-S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], + new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); + printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); + + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC); + + //Update atomic positions and restore ionic velocities + int count = 0; + int atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = (pSPARC->atom_pos[count * 3]) * scalex + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3]/S_new); // + pSPARC->atom_pos[count * 3 + 1] = (pSPARC->atom_pos[count * 3 + 1]) * scaley + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 1]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 1]/S_new); // + pSPARC->atom_pos[count * 3 + 2] = (pSPARC->atom_pos[count * 3 + 2]) * scalez + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 2]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 2]/S_new); // + pSPARC->ion_vel[count * 3] /= pSPARC->SNOSE[0]; + pSPARC->ion_vel[count * 3 + 1] /= pSPARC->SNOSE[0]; + pSPARC->ion_vel[count * 3 + 2] /= pSPARC->SNOSE[0]; + count ++; + } + + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_new; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// + + } + + + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (ISIF == 8){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (ISIF == 9){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (ISIF == 10){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + // Only |c| varies, |a| and |b| are fixed; and all angles between lattice vectors are FIXED + else if (ISIF == 11){ + gpig[0] = 0; + gpig[4] = 0; + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) / pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3,constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0/baro_const4, gpi, 3,pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int intcs1 = 0; intcs1<9; intcs1++){ + pSPARC->constraint_stress[intcs1] = thermo_const1 * (pSPARC->Pm_metric_tensor[intcs1] - gpig[intcs1]); + pSPARC->Pm_metric_tensor[intcs1] = gpig[intcs1]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int mtt1 = 0; mtt1 < 9; mtt1++){ + temp_metric_tensor[mtt1] = pSPARC->metric_tensor[mtt1]; + gpig_old[mtt1] = gpig[mtt1]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * (temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * (temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * (temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int mtn = 0; mtn < 9; mtn++){ + new_metric_tensor[mtn] = pSPARC->metric_tensor[mtn] + baro_const6 * gpig_old[mtn] + baro_const7 * gpig[mtn]; + } + + converged = true; + for (int ic1 = 0; ic1 < 9; ic1++){ + if ( fabs(new_metric_tensor[ic1] - temp_metric_tensor[ic1]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + temp_metric_tensor = transpose_and_add(new_metric_tensor); + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row][0], + new_metric_tensor[row][1], new_metric_tensor[row][2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (ISIF == 7){ + if (ISIF == 8){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (ISIF == 9){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + + for (int mtt1 = 0; mtt1 < 9; mtt1++){ + temp_metric_tensor[mtt1] = new_metric_tensor[mtt1]; + } + } + + for (int mt1 = 0; mt1 < 9; mt1++){ + pSPARC->metric_tensor[mt1] = temp_metric_tensor[mt1]; + } +} + + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ + + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-12; // tolerance criterion for checking convergence + double baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const3 = 0.5 / baro_const0; + double baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + + for (int itpmt1 = 0; itpmt1 < 9; itpmt1++){ + temp_Pm_metric_tensor[itpmt1] = pSPARC->Pm_metric_tensor[itpmt1]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, + temp_Pm_metric_tensor, 3, + pSPARC->metric_tensor[0][0], 3, + 0.0, temp_mat_1, 3); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, + matrix_1, 3, + temp_Pm_metric_tensor, 3, + 0.0, temp_mat_2, 3); + + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const5 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int ib18 = 0; ib18<9; ib18++){ + temp_mat[ib18] = internal_stress_fractional[ib18] - pSPARC->kinetic_stress[ib18] + temp_mat_2[ib18]; + temp_mat[ib18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ib18] + 0.5*pSPARC->external_stress_lattice[ib18]; + new_Pm_metric_tensor[ib18] = pSPARC->Pm_metric_tensor[ib18] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ib18]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor, 1); + + //Check convergence + converged = true; + for (int ic1 = 0; ic1 < 9; ic1++){ + if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int ic1 = 0; ic1 < 9; ic1++){ + temp_Pm_metric_tensor[ic1] = new_Pm_metric_tensor[ic1]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], + new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int c11 = 0; c11 < 9; c11++){ + pSPARC->Pm_metric_tensor[c11] = temp_Pm_metric_tensor[c11]; + } +} + + + -/* - @ brief: update momentum of thermostat and barostat variables in a half step, update momentum/mass (not velocity!) of particles in a step -*/ void updateMomentum_FirstHalf(SPARC_OBJ *pSPARC) { double ktemp; double Ga1[3]; double B[3]; double Ga3[3]; double PmA[3]; - double Sa; + + + - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update momentum of thermostat variable in a half step - ktemp = pSPARC->kB * pSPARC->thermos_T; - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp*(log(pSPARC->S_NPT_NP) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP)/pSPARC->NPT_NP_qmass; - pSPARC->Sv_NPT_NP += Sa * pSPARC->MD_dt / 2.0; - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("Sv_NPT_NP in the 1st half step is %12.9f\n", pSPARC->Sv_NPT_NP); - } - #endif - double diagElecStress[3], innerControlStress[3]; - diagElecStress[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; - diagElecStress[1] = pSPARC->stress[3] - pSPARC->stress_i[3]; - diagElecStress[2] = pSPARC->stress[5] - pSPARC->stress_i[5]; - // innerControlStress is used for adding confinements on the scale of lattice vectors, such as |a|=|b|. - innerControlStress[0] = diagElecStress[0]; - innerControlStress[1] = diagElecStress[1]; - innerControlStress[2] = diagElecStress[2]; - if (pSPARC->NPTconstraintFlag == 1) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[1]) / 2; - innerControlStress[1] = innerControlStress[0]; - } else if (pSPARC->NPTconstraintFlag == 2) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[2]) / 2; - innerControlStress[2] = innerControlStress[0]; - } else if (pSPARC->NPTconstraintFlag == 3) { - innerControlStress[1] = (diagElecStress[1] + diagElecStress[2]) / 2; - innerControlStress[2] = innerControlStress[1]; - } else if (pSPARC->NPTconstraintFlag == 4) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[1] + diagElecStress[2]) / 3; - innerControlStress[1] = innerControlStress[0]; - innerControlStress[2] = innerControlStress[0]; - } // update momentum of barostat variables in a half step for (int i = 0; i < 3; i++){ if (pSPARC->NPTscaleVecs[i] == 1) { From 23781a7ce49a0f5f5101ca65aed06a09ca0c1e0a Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Sat, 21 Mar 2026 18:25:22 -0400 Subject: [PATCH 04/87] Update_NPT_NP_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index 06c88d07..8e2d8f0a 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -819,6 +819,7 @@ typedef struct _SPARC_OBJ{ /* MD/relax options */ double *ion_vel; // Ionic velocity double *ion_accel; // Ionic acceleration + double *ion_forces_fractional; // Ionic forces in fractional coordinates double ion_T; // Ionic temperature double PE, KE, TE, TE_ext; // potential, kinetic and total energies respectively double kB; // Boltzmann constant @@ -883,18 +884,25 @@ typedef struct _SPARC_OBJ{ double pr_external; // Externally applied hydrostatic pressure, used in NPT_NP and NPH double stress_external[6]; // Externally applied anisotropic stress (applied separately from pr_external), used in NPT_NP and NPH //In NPT_NP and NPH, the target_stress[i] = pr_external+stress_external[i]; in contrast to NPT_NH where there is just target_pressure. - double NPT_NP_qmass; // fictitious mass of thermostat (qmass) used in NPT_NP double NPT_NP_bmass; // fictitious mass of barostat (bmass) used in NPT_NP - double range_x_velo; // velocity of x sidelength - double range_y_velo; // velocity of y sidelength - double range_z_velo; // velocity of z sidelength - double G_NPT_NP[3]; // G tensor, for barostat control - double Pm_NPT_NP[3]; // Pm tensor + double Pm_ion[9]; + double full_lattice[9]; // Lattice_vectors scaled by LATVEC scale + double reciprocal_lattice[9]; //Reciprocal (inverse matrix) lattice of the full cell (i.e of lattice_vector*LATVEC_SCALE), + //Note that reciprocal lattice is stored as ColumnMajor (since original lattice is rowMajor), and it lacks a factor of 2\pi + double metric_tensor[9]; // G tensor, for barostat control + double reciprocal_metric_tensor[9]; // G tensor associated with reciprocal lattice vectors, for barostat control + double initialLatVecAngles[3]; // for keeping lattice vector angles fixed in case of NPT_NP or NPH with constraints + double rotation_matrix[9]; //For rotating between actual cell, and rotated_cell + double lattice_avg_velo[9]; // Average velocity of lattice vectors + double Pm_metric_tensor[9]; // Momenta of the metric_tensor + double external_stress_lattice[9]; //external_stress matrix multiply reciprocal_metric_tensor + double external_stress_cartesian[9]; //external_stress matrix multiply reciprocal_metric_tensor + double constraint_stress[9]; // Stress generated by constraining the evolution of cell lattice vectors lengths or angles + double Kbaro; // kinetic energy of barostat variables double Ubaro; // potential energy of barostat variables - double S_NPT_NP; // S, for thermostat control - double Sv_NPT_NP; // velocity of S + double SNOSE[3]; // Thermostat control related information: Position variable of thermostat, velocity of thermostat, position variable at previous time step double Kther; // kinetic energy of thermostat variable double Uther; // potential energy of thermostat variable double Hamiltonian_NPT_NP; // Hamiltonian of the NPT-NP system From 3d5015010d830a3cb963e6744a756ef89d7496bf Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 22 Mar 2026 20:48:58 -0400 Subject: [PATCH 05/87] updated_MD updated_MD --- src/MD_updated.c | 3507 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3507 insertions(+) create mode 100644 src/MD_updated.c diff --git a/src/MD_updated.c b/src/MD_updated.c new file mode 100644 index 00000000..9c7eb4ea --- /dev/null +++ b/src/MD_updated.c @@ -0,0 +1,3507 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include + +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,":MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + NPT_NP(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + + //Calculate metric_tensor G, reciprocal metric tensor, angles between lattice vectors, rotation matrix + fetch_MD_cell_ingredients(pSPARC, false); + + pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i1 = 0; i1 < 6; i1++){ + pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable. Using a zero mass would resemble NPH ensemble, if this is the case then please choose MD_METHOD as NPH \n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MdMeth,"NPH")){ + pSPARC->NPT_NPH_qmass = 0; + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble. If choosing MD_method as NPH with nonzero thermostat mass, it would be automatically set to zero at this point\n"); + } + } + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + fetch_MD_cell_ingredients(pSPARC, false); + + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i1 = 0; i1 < 6; i1++){ + pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MdMeth,"NPH")){ + pSPARC->NPT_NPH_qmass = 0 + } + + Calculate_ionic_stress(pSPARC); + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlog v * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +*/ +void NPT_NP(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant +This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPH(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row, col; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]) + + if (update_cell == true){ + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->rotation_matrix , 3, new_cell, 3, 0.0, pSPARC->full_lattice, 3); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat(pSPARC); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt(pSPARC->metric_tensor[0]); + pSPARC->range_y = sqrt(pSPARC->metric_tensor[4]); + pSPARC->range_z = sqrt(pSPARC->metric_tensor[8]); + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update new angles between lattice vectors + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + //Update reciprocal lattice vectors, reciprocal metric tensor + + } + + for (int i = 0; i<9; i++){ + old_cell[i] = pSPARC->full_lattice[i] + } + + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9] + double S_inv[9] = {0} + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3,3,old_cell,3,S,U,3,VT,3,superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(cblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate its the vecocity of cell lattice vectors + else if { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + pSPARC->lattice_avg_velo[i] = 0.0; + } + + temp_mat_2[0] = temp_mat_3[0] / (2.0 * new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->rotation_matrix, 3, temp_mat_2, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int count = 0; + + pSPARC->KE = 0.0; + int ityp, atm; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); + count ++; + } + } + pSPARC->KE = pSPARC->KE / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]); + double temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ + double kinetic_stress[9] = {0.0}; + + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + free(ion_vel_fractional); + + kinetic_stress[3] = kinetic_stress[1]; + kinetic_stress[6] = kinetic_stress[2]; + kinetic_stress[7] = kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), kinetic_stress, 1); + + for (int i = 0; i < 9; i++){ + pSPARC->total_internal_stress[i] = ( kinetic_stress[i] - pSPARC->internal_stress[i][i] - pSPARC->constraint_stress) + } + + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); + + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); + +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + double ktemp; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + // Calculating kinetic energy of ions + int ityp, atm; + cblas_dscal(pSPARC->n_atom*3,pSPARC->SNOSE[2],pSPARC->ion_vel); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(pSPARC->n_atom*3, baro_const1, pSPARC->Pm_metric_tensor, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b,1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9,pSPARC->external_stress_lattice,1,pSPARC->metric_tensor,1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + //Initialize some useful constants + double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + + double sumAllHamilTerms = pSPARC->Etot;//Potential; Term 2 in Eqn.10 in Hernandez paper + sumAllHamilTerms += pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + #endif + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// + + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa = 0.0; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + ktemp = pSPARC->kB * pSPARC->thermos_T; + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; + pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + } + + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; + + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: so reciprocal lattice vectors are columns) + for (int i = 0; i<9; i++){ + temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3,pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5*pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i<9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5*pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + if (ISIF == 10){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + + if (ISIF == 11){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9,temp_mat_a, 1, temp_mat_b,1);//Kinetic + pSPARC->Ubaro = 0.5 * cblas_ddot(9,pSPARC->external_stress_lattice,1,pSPARC->metric_tensor,1); //Potential + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + double thermo_const0 = pSPARC->MD_dt*pSPARC->SNOSE[0] / 2.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + + //Now write Intenal pressure, external pressure to a file + + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + //Calculate/Update total energy (Hamiltonian) + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + double constant_of_motion = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); + //Optionall write all individual energy contributions to the Hamiltonian to an output file + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC); + + //Now impose the constraints on it + if (ISIF == 10){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + + if (ISIF == 11){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + ktemp = pSPARC->kB * pSPARC->thermos_T; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * (log(pSPARC->SNOSE[0])+1) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + if ((1.0 - factor*pSPARC->MD_dt/pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + exit(EXIT_FAILURE); + } + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("Sv_NPT_NP in the 2nd half step is %12.9f\n", pSPARC->Sv_NPT_NP); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = 1.0; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT ensemble + S_temp = pSPARC->SNOSE[0]; + + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp-S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], + new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); + printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); + + //Before updating cell parameters, compute atom positions in fractional coordinates + double *atom_pos_fractional = (double *)calloc(3 * n_atoms, sizeof(double)); + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); + count++ + } + + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * pSPARC->atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * pSPARC->atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[6] * pSPARC->atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); + count++; + } + free(atom_pos_fractional); + + //Update atomic positions and restore ionic velocities + int count = 0; + int atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * (pSPARC->ion_vel[count * 3] / pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3] / S_new); // + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * (pSPARC->ion_vel[count * 3 + 1] / pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 1] / S_new); // + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * (pSPARC->ion_vel[count * 3 + 2] / pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 2] / S_new); // + pSPARC->ion_vel[count * 3] /= pSPARC->SNOSE[0]; + pSPARC->ion_vel[count * 3 + 1] /= pSPARC->SNOSE[0]; + pSPARC->ion_vel[count * 3 + 2] /= pSPARC->SNOSE[0]; + count ++; + } + + //Update kinetic energy and kinetic stress + pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + } + + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_new; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// + + +} + + + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (ISIF == 8){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (ISIF == 9){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (ISIF == 10){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + // Only |c| varies, |a| and |b| are fixed; and all angles between lattice vectors are FIXED + else if (ISIF == 11){ + gpig[0] = 0; + gpig[4] = 0; + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) / pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3,constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0/baro_const4, gpi, 3,pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * (temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * (temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * (temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row][0], + new_metric_tensor[row][1], new_metric_tensor[row][2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (ISIF >= 7){ + if (ISIF == 8){ + new_metric_tensor[0] = ( new_metric_tensor[0] + ne w_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (ISIF == 9){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; mt1 < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } +} + + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ + + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-12; // tolerance criterion for checking convergence + double baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const3 = 0.5 / baro_const0; + double baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, + temp_Pm_metric_tensor, 3, + pSPARC->metric_tensor, 3, + 0.0, temp_mat_1, 3); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, + temp_mat_1, 3, + temp_Pm_metric_tensor, 3, + 0.0, temp_mat_2, 3); + + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int ic1 = 0; ic1 < 9; ic1++){ + if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], + new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + } +} + + + + +void updateMomentum_FirstHalf(SPARC_OBJ *pSPARC) { + double ktemp; + double Ga1[3]; + double B[3]; + double Ga3[3]; + double PmA[3]; + + + + + + // update momentum of barostat variables in a half step + for (int i = 0; i < 3; i++){ + if (pSPARC->NPTscaleVecs[i] == 1) { + Ga1[i] = innerControlStress[i] * pSPARC->volumeCell / 2.0 / pSPARC->G_NPT_NP[i]; + B[i] = 1.0 / (pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) * pow(pSPARC->Pm_NPT_NP[i],2.0) * pSPARC->G_NPT_NP[i]; + Ga3[i] = (pSPARC->prtarget * pSPARC->volumeCell / 2.0 - pSPARC->Kbaro) / pSPARC->G_NPT_NP[i]; + PmA[i] = Ga1[i] + B[i] + Ga3[i]; + pSPARC->Pm_NPT_NP[i] -= pSPARC->MD_dt * pSPARC->S_NPT_NP / 2.0 * PmA[i]; + #ifdef DEBUG + if (rank == 0){ + // printf("pSPARC->pres is %12.9f, pSPARC->pres_i is %12.9f, pSPARC->volumeCell is %12.9f, pSPARC->G_NPT_NP[%d] is %12.9f\n", pSPARC->pres, pSPARC->pres_i, pSPARC->volumeCell, i, pSPARC->G_NPT_NP[i]); + printf("PmA[%d] is %12.9f\n", i, PmA[i]); + printf("pSPARC->Pm_NPT_NP[%d] in 1st half step is %12.9f\n", i, pSPARC->Pm_NPT_NP[i]); + } + #endif + } + } + // update momentum/mass of particles (reminder: not velocity!) in a step + int ityp, atm; + int count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] = pSPARC->ion_vel[count * 3] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3 + 2]; + // for now they are not velocity! + count ++; + } + } +} + +/* + @ brief: update momentum of thermostat and barostat variables in the second half step +*/ +void updateMomentum_SecondHalf(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double PmTmp[3], PmNew[3]; + int i; + for (i = 0; i < 3; i++){ + PmTmp[i] = pSPARC->Pm_NPT_NP[i]; + } + // update momentum of barostat variables in the second half time step + int judge = 0; + int timeIter = 0; + double G1[3], Gatmp1[3], Gatmp2[3], Gatmp3[3], PmAtmp[3]; + double KbaroTmp = 0; + + double diagElecStress[3], innerControlStress[3]; + diagElecStress[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; + diagElecStress[1] = pSPARC->stress[3] - pSPARC->stress_i[3]; + diagElecStress[2] = pSPARC->stress[5] - pSPARC->stress_i[5]; + // innerControlStress is used for adding confinements on the scale of lattice vectors, such as |a|=|b|. + innerControlStress[0] = diagElecStress[0]; + innerControlStress[1] = diagElecStress[1]; + innerControlStress[2] = diagElecStress[2]; + if (pSPARC->NPTconstraintFlag == 1) { + innerControlStress[0] = (diagElecStress[0] + diagElecStress[1]) / 2; + innerControlStress[1] = innerControlStress[0]; + } else if (pSPARC->NPTconstraintFlag == 2) { + innerControlStress[0] = (diagElecStress[0] + diagElecStress[2]) / 2; + innerControlStress[2] = innerControlStress[0]; + } else if (pSPARC->NPTconstraintFlag == 3) { + innerControlStress[1] = (diagElecStress[1] + diagElecStress[2]) / 2; + innerControlStress[2] = innerControlStress[1]; + } else if (pSPARC->NPTconstraintFlag == 4) { + innerControlStress[0] = (diagElecStress[0] + diagElecStress[1] + diagElecStress[2]) / 3; + innerControlStress[1] = innerControlStress[0]; + innerControlStress[2] = innerControlStress[0]; + } + + while (judge == 0) { + timeIter++; + KbaroTmp = 0; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + G1[i] = 1 / (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) * PmTmp[i] * pSPARC->G_NPT_NP[i]; + KbaroTmp += (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) / 2 * pow(G1[i],2.0); + } + } + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + Gatmp1[i] = innerControlStress[i] * pSPARC->volumeCell / 2.0 / pSPARC->G_NPT_NP[i]; + Gatmp2[i] = G1[i] * PmTmp[i]; + Gatmp3[i] = (pSPARC->prtarget * pSPARC->volumeCell / 2.0 - KbaroTmp) / pSPARC->G_NPT_NP[i]; + PmAtmp[i] = Gatmp1[i] + Gatmp2[i] + Gatmp3[i]; + PmNew[i] = pSPARC->Pm_NPT_NP[i] - pSPARC->MD_dt / 2.0 * pSPARC->S_NPT_NP * PmAtmp[i]; + } + } + judge = 1; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + if (fabs(PmNew[i] - PmTmp[i]) > 1e-7){ + judge = 0; + } + PmTmp[i] = PmNew[i]; + } + } + if (timeIter > pSPARC->maxTimeIter){ + judge = 1; + if (rank == 0) + printf("Reminder: The barostat momentum Pm_NPT_NP does not converge in %d timesteps.\n", pSPARC->maxTimeIter); + } + } + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + pSPARC->Pm_NPT_NP[i] = PmTmp[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_NPT_NP[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_NPT_NP[i]); + #endif + } + } + + // update thermostat velocity in the second half time step + pSPARC->KE = 0.0; + int ityp, atm; + int count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + pSPARC->KE /= pow(pSPARC->S_NPT_NP, 2.0); // from momentum/mass to true velocity + pSPARC->Kbaro = 0.0; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + G1[i] = 1.0 / (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) * PmTmp[i] * pSPARC->G_NPT_NP[i]; + pSPARC->Kbaro += (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) / 2.0 * pow(G1[i],2.0); + } + } + double factor; + double ktemp = pSPARC->kB * pSPARC->thermos_T; + factor = pSPARC->MD_dt / 2.0 * (pSPARC->dof*ktemp*(log(pSPARC->S_NPT_NP) + 1) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP) - pSPARC->NPT_NP_qmass*pSPARC->Sv_NPT_NP; + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + if ((1.0 - factor*pSPARC->MD_dt/pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + exit(EXIT_FAILURE); + } + pSPARC->Sv_NPT_NP = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("Sv_NPT_NP in the 2nd half step is %12.9f\n", pSPARC->Sv_NPT_NP); + #endif +} + +/* + @ brief: update positions of particles, value of thermostat variable and barostat variables in the step +*/ +void updatePosition(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + int judge = 0; + // update value of thermostat variable S_NPT_NP + double Stemp = pSPARC->S_NPT_NP; + double Snew; + int timeIter = 0; + while (judge == 0) { + timeIter++; + Snew = pSPARC->S_NPT_NP + pSPARC->MD_dt / 2.0 * (pSPARC->S_NPT_NP + Stemp) * pSPARC->Sv_NPT_NP; + if (fabs(Snew - Stemp) < 1e-7) { + judge = 1; + } + Stemp = Snew; + if (timeIter > pSPARC->maxTimeIter) { + judge = 1; + if (rank == 0) + printf("Reminder: The value of thermostat variable S_NPT_NP does not converge in %d iterations.\n", pSPARC->maxTimeIter); + } + } + #ifdef DEBUG + if (rank == 0) + printf("Stemp is %12.9f\n", Stemp); + #endif + // update values of barostat variables G_NPT_NP + double Gtmp[3], Gnew[3], Gpig[3], GpigOld[3]; + int i; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + Gtmp[i] = pSPARC->G_NPT_NP[i]; + GpigOld[i] = pow(pSPARC->G_NPT_NP[i], 2.0) * pSPARC->Pm_NPT_NP[i]; + } + } + judge = 0; timeIter = 0; + while (judge == 0){ + timeIter++; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + Gpig[i] = pow(Gtmp[i], 2.0) * pSPARC->Pm_NPT_NP[i]; + Gnew[i] = pSPARC->G_NPT_NP[i] + pSPARC->MD_dt / 2.0 * (pSPARC->S_NPT_NP/(pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0))*GpigOld[i] + Stemp/(pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0))*Gpig[i]); + } + } + judge = 1; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + if (fabs(Gnew[i] - Gtmp[i]) > 1e-7) { + judge = 0; + } + Gtmp[i] = Gnew[i]; + } + } + if (timeIter > pSPARC->maxTimeIter) { + judge = 1; + if (rank == 0) + printf("Reminder: The barostat variables G_NPT_NP do not converge in %d iterations.\n", pSPARC->maxTimeIter); + } + } + double G3[3]; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + pSPARC->G_NPT_NP[i] = Gtmp[i]; + G3[i] = pow(Gtmp[i], 2.0) * pSPARC->Pm_NPT_NP[i]; + } + } + #ifdef DEBUG + if (rank == 0) { + printf("pSPARC->G_NPT_NP[0] is %12.9f\n", pSPARC->G_NPT_NP[0]); + printf("pSPARC->G_NPT_NP[1] is %12.9f\n", pSPARC->G_NPT_NP[1]); + printf("pSPARC->G_NPT_NP[2] is %12.9f\n", pSPARC->G_NPT_NP[2]); + } + #endif + // update side lengths of cells and velocities of them + double scalex = sqrt(pSPARC->G_NPT_NP[0]) / pSPARC->range_x; + pSPARC->range_x = sqrt(pSPARC->G_NPT_NP[0]); + double scaley = sqrt(pSPARC->G_NPT_NP[1]) / pSPARC->range_y; + pSPARC->range_y = sqrt(pSPARC->G_NPT_NP[1]); + double scalez = sqrt(pSPARC->G_NPT_NP[2]) / pSPARC->range_z; + pSPARC->range_z = sqrt(pSPARC->G_NPT_NP[2]); + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + if (pSPARC->NPTscaleVecs[0] == 1) + pSPARC->range_x_velo = G3[0] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_x; + else + pSPARC->range_x_velo = 0.0; + if (pSPARC->NPTscaleVecs[1] == 1) + pSPARC->range_y_velo = G3[1] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_y; + else + pSPARC->range_y_velo = 0.0; + if (pSPARC->NPTscaleVecs[2] == 1) + pSPARC->range_z_velo = G3[2] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_z; + else + pSPARC->range_z_velo = 0.0; + // update positions of particles, and restore the values of particle velocities + int count = 0; + int atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = (pSPARC->atom_pos[count * 3]) * scalex + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3]/Stemp); // + pSPARC->atom_pos[count * 3 + 1] = (pSPARC->atom_pos[count * 3 + 1]) * scaley + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 1]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 1]/Stemp); // + pSPARC->atom_pos[count * 3 + 2] = (pSPARC->atom_pos[count * 3 + 2]) * scalez + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 2]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 2]/Stemp); // + pSPARC->ion_vel[count * 3] /= Stemp; + pSPARC->ion_vel[count * 3 + 1] /= Stemp; + pSPARC->ion_vel[count * 3 + 2] /= Stemp; + count ++; + } + pSPARC->S_NPT_NP = Stemp; +} + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + else + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the qunatities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE/pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + // Compute Ionic stress/pressure + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; + int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(sizeof(double), 9); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":NPT_NP_Sv: %.15g\n", pSPARC->Sv_NPT_NP); // velocity of virtual thermal parameter + fprintf(mdout,":NPT_NP_Pm: %.15g %.15g %.15g\n", pSPARC->Pm_NPT_NP[0], pSPARC->Pm_NPT_NP[1], pSPARC->Pm_NPT_NP[2]); // velocity of virtual baro parameter + fprintf(mdout,":NPT_NP_S: %.15g\n", pSPARC->S_NPT_NP); // value of virtual thermal parameter + fprintf(mdout,":NPT_NP_range_x_velo: %.15g\n", pSPARC->range_x_velo); // velocity of virtual x baro parameter + fprintf(mdout,":NPT_NP_range_y_velo: %.15g\n", pSPARC->range_y_velo); // velocity of virtual y baro parameter + fprintf(mdout,":NPT_NP_range_z_velo: %.15g\n", pSPARC->range_z_velo); // velocity of virtual z baro parameter + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + // Print temperature + fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); + + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_Sv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->Sv_NPT_NP); + else if (strcmpi(str,":NPT_NP_S:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->S_NPT_NP); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":NPT_NP_range_x_velo:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->range_x_velo); + else if (strcmpi(str,":NPT_NP_range_y_velo:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->range_y_velo); + else if (strcmpi(str,":NPT_NP_range_z_velo:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->range_z_velo); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_T i); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->Sv_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->S_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->Sv_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->S_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + + \ No newline at end of file From b0a8f2831bcfc022ced75f082b146720dfd12b24 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 24 Mar 2026 11:34:01 -0400 Subject: [PATCH 06/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- .../md_copy_metric_tensor_extra_used.c | 3435 +++++++++++++++++ src/initialization.c | 20 +- src/md.c | 963 ++--- 3 files changed, 3844 insertions(+), 574 deletions(-) create mode 100644 src/include/md_copy_metric_tensor_extra_used.c diff --git a/src/include/md_copy_metric_tensor_extra_used.c b/src/include/md_copy_metric_tensor_extra_used.c new file mode 100644 index 00000000..d1017a2a --- /dev/null +++ b/src/include/md_copy_metric_tensor_extra_used.c @@ -0,0 +1,3435 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include + +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,":MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + NPT_NP(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + + //Calculate metric_tensor G, reciprocal metric tensor, angles between lattice vectors, rotation matrix + fetch_MD_cell_ingredients(pSPARC); + + pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i1 = 0; i1 < 6; i1++){ + pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable. Using a zero mass would resemble NPH ensemble, if this is the case then please choose MD_METHOD as NPH \n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MdMeth,"NPH")){ + pSPARC->NPT_NPH_qmass = 0 + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble. If choosing MD_method as NPH with nonzero thermostat mass, it would be automatically set to zero at this point\n"); + } + } + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + fetch_MD_cell_ingredients(pSPARC); + + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i1 = 0; i1 < 6; i1++){ + pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MdMeth,"NPH")){ + pSPARC->NPT_NPH_qmass = 0 + } + + Calculate_ionic_stress(pSPARC); + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +*/ +void NPT_NP (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant +This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + pSPARC->NPT_NP_qmass = 0; + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1, int flag){ + + //Pure transpose + if (flag==0){ + double tmp; + // Swap (0,1) with (1,0) + tmp = matrix1[1]; matrix1[1] = matrix1[3]; matrix1[3] = tmp; + // Swap (0,2) with (2,0) + tmp = matrix1[2]; matrix1[2] = matrix1[6]; matrix1[6] = tmp; + // Swap (1,2) with (2,1) + tmp = matrix1[5]; matrix1[5] = matrix1[7]; matrix1[7] = tmp; + } + + //performs matrix1 = matrix1 + transpose(matrix1) + else if (flag==1){ + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; + } +} + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC){ + + double old_cell[9]; double new_cell[9]; + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row, col; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3]/sqrt(metric_tensor[0]); + new_cell[4] = sqrt(pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3]*pSPARC->metric_tensor[3])/pSPARC->metric_tensor[0]; + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6]/sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = (pSPARC->metric_tensor[0]*pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3]*pSPARC->metric_tensor[6])/sqrt(pSPARC->metric_tensor[0]*pSPARC->metric_tensor[0]*pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0]*pSPARC->metric_tensor[3]*pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]) + + for (int i = 0; i<9; i++){ + old_cell[i] = pSPARC->full_lattice[i] + } + + // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = cblas_ddot(3,&lattice1[3], 1.0, &lattice1[6],1.0 )/(pSPARC->range_y*pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = cblas_ddot(3,&lattice1[0], 1.0, &lattice1[6],1.0 )/(pSPARC->range_x*pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = cblas_ddot(3,&lattice1[0], 1.0, &lattice1[3],1.0 )/(pSPARC->range_x*pSPARC->range_y); // cos_gamma + + // Calculate the inverse of lattice-vector + double U[9], S[3], VT[9], superb[2], temp_mat[9] + double S_inv[9] = {0} + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3,3,old_cell,3,S,U,3,VT,3,superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since lattice1 is rowMajor, reciprocal_lattice1 is columnMajor + // i.e. the reciprocal lattice vectors (of lattice1) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPRAC->reciprocal_lattice, 3); + + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasTrans, CblasTrans, 3, 3, 3, 1.0, pSPRAC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + // Now computing reciprocal metric tensor, + cblas_dgemm(cblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPRAC->reciprocal_lattice, 3, pSPRAC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + + //TODO: Update cell volume + //TODO: Update Jacbdet + //TODO: Update LatVec + //TODO: Update LatUvec + + //Computing velocity of lattice vectors + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int iu1 = 0; iu1 < 9; iu1++){ + temp_mat_3[iu1] = pSPARC->Pm_metric_tensor; + } + + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int iu1 = 0; iu1 < 9; iu1++){ + temp_mat_2[iu1] = 0.0; + pSPARC->lattice_avg_velo[iu1] = 0.0; + } + + temp_mat_2[0] = temp_mat_3[0] / (2.0 * new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->rotation_matrix , 3, temp_mat_2, 3, 0.0, pSPARC->lattice_avg_velo, 3); + +} + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + double vec1[3]; + int count = 0; + + pSPARC->KE = 0.0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + cblas_dgemv(CblasRowMajor, CblasNoTrans,3,3,1.0,pSPARC->reciprocal_metric_tensor,3,&pSPARC->Pm_ion[count*3],1,0.0,vec1,1); + pSPARC->KE += cblas_ddot(3,vec1,1, &pSPARC->Pm_ion[count*3],1)/pSPARC->Mass[ityp]; + count ++; + } + } + pSPARC->KE = 0.5*pSPARC->KE/(pSPARC->SNOSE[0]*pSPARC->SNOSE[0]); + double temperature = 2.0*pSPARC->KE/(pSPARC->dof*pSPARC->kB) +} + + +void Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ + double kinetic_stress[9] = {0.0}; + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count*3] = (pSPARC->reciprocal_metric_tensor[0] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[1] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[2] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count*3+1] = (pSPARC->reciprocal_metric_tensor[3] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[4] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[5] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count*3+2] = (pSPARC->reciprocal_metric_tensor[6] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[7] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[8] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; + + } + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3]; + kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+1]; + kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+2]; + kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+1]; + kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+2]; + count++; + } + } + + kinetic_stress[3] = kinetic_stress[1]; + kinetic_stress[6] = kinetic_stress[2]; + kinetic_stress[7] = kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), kinetic_stress, 1); + + for (int its1 = 0; its1<9; its1++){ + pSPARC->total_internal_stress[its1] = ( kinetic_stress[its1] - pSPARC->internal_stress - pSPARC->constraint_stress) + } + + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); + + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); + +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + pSPARC->ionic_forces_fractional = (double *)malloc(pSPARC->n_atom*3 * sizeof(double) ); + + //Initialize some useful constants + double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10a)----------------------------------// + // Calculating momentum of ions + int ityp, atm; + int count = 0; + cblas_dscal(pSPARC->n_atom*3,pSPARC->SNOSE[2],pSPARC->ion_vel,1); + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + cblas_dgemv(CblasRowMajor,CblasNoTrans,3,3,pSPARC->Mass[ityp],pSPARC->metric_tensor,3,&pSPARC->ion_vel[count*3],1,0.0,&pSPARC->Pm_ion[count*3],1) + count ++; + } + } + + + // Calculating kinetic energy of ions + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor,1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(pSPARC->n_atom*3,baro_const1,pSPARC->Pm_metric_tensor,1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9,temp_mat_a, 1, temp_mat_b,1);//Kinetic + pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell; //Potential + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5*cblas_ddot(9,pSPARC->external_stress_lattice,1,pSPARC->metric_tensor,1) + + double sumAllHamilTerms = pSPARC->Etot; + sumAllHamilTerms += pSPARC->KE + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + #endif + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10a)----------------------------------// + + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + ktemp = pSPARC->kB * pSPARC->thermos_T; + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; + pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; + + // Update the kinetic energy of the thermostat + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + } + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress[4] = pSPARC->stress[3]; internal_stress[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress[2] = pSPARC->stress[2]; internal_stress[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress[6] = pSPARC->stress[2]; internal_stress[7] = pSPARC->stress[4]; + + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: so reciprocal lattice vectors are columns) + for (int itma1 = 0; itma1<9; itma1++){ + temp_mat_a[itma1] = pSPARC->reciprocal_lattice[itma1]; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3,pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int ix1 = 0; ix1<9; ix1++){ + temp_Pm_mat[ix1] = pSPARC->Pm_metric_tensor[ix1]; + } + + // Eqn. 18h Hernandez paper + for (int ih18 = 0; ih18<9; ih18++){ + temp_mat[ih18] = internal_stress_fractional[ih18] - pSPARC->kinetic_stress[ih18] + temp_mat_b[ih18]; + temp_mat[ih18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ih18] + 0.5*pSPARC->external_stress_lattice[ih18]; + pSPARC->Pm_metric_tensor[ih18] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ih18]; + } + + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + + for (int ih18 = 0; ih18<9; ih18++){ + temp_mat[ih18] = internal_stress_fractional[ih18] + pSPARC->constraint_stress[ih18] - pSPARC->kinetic_stress[ih18] + temp_mat_b[ih18]; + temp_mat[ih18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ih18] + 0.5*pSPARC->external_stress_lattice[ih18]; + pSPARC->Pm_metric_tensor[ih18] = temp_Pm_mat[ih18] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ih18]; + } + + if (ISIF == 10){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + + if (ISIF == 11){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9,temp_mat_a, 1, temp_mat_b,1);//Kinetic + + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + double thermo_const0 = pSPARC->MD_dt*pSPARC->SNOSE[0] / 2.0; + for(int natm1 = 0; natm1 < pSPARC->n_atom; natm1++){ + pSPARC->ionic_forces_fractional[natm1*3] = (pSPARC->full_lattice[0] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[1] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[2] * pSPARC->forces[natm1*3+2]); + pSPARC->ionic_forces_fractional[natm1*3+1] = (pSPARC->full_lattice[3] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[4] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[5] * pSPARC->forces[natm1*3+2]); + pSPARC->ionic_forces_fractional[natm1*3+2] = (pSPARC->full_lattice[6] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[7] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[8] * pSPARC->forces[natm1*3+2]); + + pSPARC->Pm_ion[natm1*3] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3]; + pSPARC->Pm_ion[natm1*3+1] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+1]; + pSPARC->Pm_ion[natm1*3+2] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+2]; + } + + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + + //Now write Intenal pressure, external pressure to a file + + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + //Calculate/Update total energy (Hamiltonian) + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + double constant_of_motion = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); + //Optionall write all individual energy contributions to the Hamiltonian to an output file + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + for(int natm1 = 0; natm1 < pSPARC->n_atom; natm1++){ + pSPARC->Pm_ion[natm1*3] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3]; + pSPARC->Pm_ion[natm1*3+1] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+1]; + pSPARC->Pm_ion[natm1*3+2] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+2]; + } + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC); + + //Now impose the constraints on it + if (ISIF == 10){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + + if (ISIF == 11){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + double ktemp = pSPARC->kB * pSPARC->thermos_T; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * (log(pSPARC->SNOSE[0])+1) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + if ((1.0 - factor*pSPARC->MD_dt/pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + exit(EXIT_FAILURE); + } + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("Sv_NPT_NP in the 2nd half step is %12.9f\n", pSPARC->Sv_NPT_NP); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new; double S_temp; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT ensemble + S_temp = pSPARC->SNOSE[0]; + + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp-S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], + new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); + printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); + + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC); + + //Update atomic positions and restore ionic velocities + int count = 0; + int atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = (pSPARC->atom_pos[count * 3]) * scalex + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3]/S_new); // + pSPARC->atom_pos[count * 3 + 1] = (pSPARC->atom_pos[count * 3 + 1]) * scaley + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 1]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 1]/S_new); // + pSPARC->atom_pos[count * 3 + 2] = (pSPARC->atom_pos[count * 3 + 2]) * scalez + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 2]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 2]/S_new); // + pSPARC->ion_vel[count * 3] /= pSPARC->SNOSE[0]; + pSPARC->ion_vel[count * 3 + 1] /= pSPARC->SNOSE[0]; + pSPARC->ion_vel[count * 3 + 2] /= pSPARC->SNOSE[0]; + count ++; + } + + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_new; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// + + +} + + + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (ISIF == 8){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (ISIF == 9){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (ISIF == 10){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + // Only |c| varies, |a| and |b| are fixed; and all angles between lattice vectors are FIXED + else if (ISIF == 11){ + gpig[0] = 0; + gpig[4] = 0; + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) / pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3,constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0/baro_const4, gpi, 3,pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int intcs1 = 0; intcs1<9; intcs1++){ + pSPARC->constraint_stress[intcs1] = thermo_const1 * (pSPARC->Pm_metric_tensor[intcs1] - gpig[intcs1]); + pSPARC->Pm_metric_tensor[intcs1] = gpig[intcs1]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int mtt1 = 0; mtt1 < 9; mtt1++){ + temp_metric_tensor[mtt1] = pSPARC->metric_tensor[mtt1]; + gpig_old[mtt1] = gpig[mtt1]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * (temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * (temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * (temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int mtn = 0; mtn < 9; mtn++){ + new_metric_tensor[mtn] = pSPARC->metric_tensor[mtn] + baro_const6 * gpig_old[mtn] + baro_const7 * gpig[mtn]; + } + + converged = true; + for (int ic1 = 0; ic1 < 9; ic1++){ + if ( fabs(new_metric_tensor[ic1] - temp_metric_tensor[ic1]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + temp_metric_tensor = transpose_and_add(new_metric_tensor); + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row][0], + new_metric_tensor[row][1], new_metric_tensor[row][2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (ISIF == 7){ + if (ISIF == 8){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (ISIF == 9){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + + for (int mtt1 = 0; mtt1 < 9; mtt1++){ + temp_metric_tensor[mtt1] = new_metric_tensor[mtt1]; + } + } + + for (int mt1 = 0; mt1 < 9; mt1++){ + pSPARC->metric_tensor[mt1] = temp_metric_tensor[mt1]; + } +} + + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ + + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-12; // tolerance criterion for checking convergence + double baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const3 = 0.5 / baro_const0; + double baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + + for (int itpmt1 = 0; itpmt1 < 9; itpmt1++){ + temp_Pm_metric_tensor[itpmt1] = pSPARC->Pm_metric_tensor[itpmt1]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, + temp_Pm_metric_tensor, 3, + pSPARC->metric_tensor[0][0], 3, + 0.0, temp_mat_1, 3); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, + matrix_1, 3, + temp_Pm_metric_tensor, 3, + 0.0, temp_mat_2, 3); + + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const5 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int ib18 = 0; ib18<9; ib18++){ + temp_mat[ib18] = internal_stress_fractional[ib18] - pSPARC->kinetic_stress[ib18] + temp_mat_2[ib18]; + temp_mat[ib18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ib18] + 0.5*pSPARC->external_stress_lattice[ib18]; + new_Pm_metric_tensor[ib18] = pSPARC->Pm_metric_tensor[ib18] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ib18]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor, 1); + + //Check convergence + converged = true; + for (int ic1 = 0; ic1 < 9; ic1++){ + if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int ic1 = 0; ic1 < 9; ic1++){ + temp_Pm_metric_tensor[ic1] = new_Pm_metric_tensor[ic1]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], + new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int c11 = 0; c11 < 9; c11++){ + pSPARC->Pm_metric_tensor[c11] = temp_Pm_metric_tensor[c11]; + } +} + + + + +void updateMomentum_FirstHalf(SPARC_OBJ *pSPARC) { + double ktemp; + double Ga1[3]; + double B[3]; + double Ga3[3]; + double PmA[3]; + + + + + + // update momentum of barostat variables in a half step + for (int i = 0; i < 3; i++){ + if (pSPARC->NPTscaleVecs[i] == 1) { + Ga1[i] = innerControlStress[i] * pSPARC->volumeCell / 2.0 / pSPARC->G_NPT_NP[i]; + B[i] = 1.0 / (pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) * pow(pSPARC->Pm_NPT_NP[i],2.0) * pSPARC->G_NPT_NP[i]; + Ga3[i] = (pSPARC->prtarget * pSPARC->volumeCell / 2.0 - pSPARC->Kbaro) / pSPARC->G_NPT_NP[i]; + PmA[i] = Ga1[i] + B[i] + Ga3[i]; + pSPARC->Pm_NPT_NP[i] -= pSPARC->MD_dt * pSPARC->S_NPT_NP / 2.0 * PmA[i]; + #ifdef DEBUG + if (rank == 0){ + // printf("pSPARC->pres is %12.9f, pSPARC->pres_i is %12.9f, pSPARC->volumeCell is %12.9f, pSPARC->G_NPT_NP[%d] is %12.9f\n", pSPARC->pres, pSPARC->pres_i, pSPARC->volumeCell, i, pSPARC->G_NPT_NP[i]); + printf("PmA[%d] is %12.9f\n", i, PmA[i]); + printf("pSPARC->Pm_NPT_NP[%d] in 1st half step is %12.9f\n", i, pSPARC->Pm_NPT_NP[i]); + } + #endif + } + } + // update momentum/mass of particles (reminder: not velocity!) in a step + int ityp, atm; + int count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] = pSPARC->ion_vel[count * 3] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3 + 2]; + // for now they are not velocity! + count ++; + } + } +} + +/* + @ brief: update momentum of thermostat and barostat variables in the second half step +*/ +void updateMomentum_SecondHalf(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double PmTmp[3], PmNew[3]; + int i; + for (i = 0; i < 3; i++){ + PmTmp[i] = pSPARC->Pm_NPT_NP[i]; + } + // update momentum of barostat variables in the second half time step + int judge = 0; + int timeIter = 0; + double G1[3], Gatmp1[3], Gatmp2[3], Gatmp3[3], PmAtmp[3]; + double KbaroTmp = 0; + + double diagElecStress[3], innerControlStress[3]; + diagElecStress[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; + diagElecStress[1] = pSPARC->stress[3] - pSPARC->stress_i[3]; + diagElecStress[2] = pSPARC->stress[5] - pSPARC->stress_i[5]; + // innerControlStress is used for adding confinements on the scale of lattice vectors, such as |a|=|b|. + innerControlStress[0] = diagElecStress[0]; + innerControlStress[1] = diagElecStress[1]; + innerControlStress[2] = diagElecStress[2]; + if (pSPARC->NPTconstraintFlag == 1) { + innerControlStress[0] = (diagElecStress[0] + diagElecStress[1]) / 2; + innerControlStress[1] = innerControlStress[0]; + } else if (pSPARC->NPTconstraintFlag == 2) { + innerControlStress[0] = (diagElecStress[0] + diagElecStress[2]) / 2; + innerControlStress[2] = innerControlStress[0]; + } else if (pSPARC->NPTconstraintFlag == 3) { + innerControlStress[1] = (diagElecStress[1] + diagElecStress[2]) / 2; + innerControlStress[2] = innerControlStress[1]; + } else if (pSPARC->NPTconstraintFlag == 4) { + innerControlStress[0] = (diagElecStress[0] + diagElecStress[1] + diagElecStress[2]) / 3; + innerControlStress[1] = innerControlStress[0]; + innerControlStress[2] = innerControlStress[0]; + } + + while (judge == 0) { + timeIter++; + KbaroTmp = 0; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + G1[i] = 1 / (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) * PmTmp[i] * pSPARC->G_NPT_NP[i]; + KbaroTmp += (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) / 2 * pow(G1[i],2.0); + } + } + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + Gatmp1[i] = innerControlStress[i] * pSPARC->volumeCell / 2.0 / pSPARC->G_NPT_NP[i]; + Gatmp2[i] = G1[i] * PmTmp[i]; + Gatmp3[i] = (pSPARC->prtarget * pSPARC->volumeCell / 2.0 - KbaroTmp) / pSPARC->G_NPT_NP[i]; + PmAtmp[i] = Gatmp1[i] + Gatmp2[i] + Gatmp3[i]; + PmNew[i] = pSPARC->Pm_NPT_NP[i] - pSPARC->MD_dt / 2.0 * pSPARC->S_NPT_NP * PmAtmp[i]; + } + } + judge = 1; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + if (fabs(PmNew[i] - PmTmp[i]) > 1e-7){ + judge = 0; + } + PmTmp[i] = PmNew[i]; + } + } + if (timeIter > pSPARC->maxTimeIter){ + judge = 1; + if (rank == 0) + printf("Reminder: The barostat momentum Pm_NPT_NP does not converge in %d timesteps.\n", pSPARC->maxTimeIter); + } + } + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + pSPARC->Pm_NPT_NP[i] = PmTmp[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_NPT_NP[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_NPT_NP[i]); + #endif + } + } + + // update thermostat velocity in the second half time step + pSPARC->KE = 0.0; + int ityp, atm; + int count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + pSPARC->KE /= pow(pSPARC->S_NPT_NP, 2.0); // from momentum/mass to true velocity + pSPARC->Kbaro = 0.0; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + G1[i] = 1.0 / (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) * PmTmp[i] * pSPARC->G_NPT_NP[i]; + pSPARC->Kbaro += (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) / 2.0 * pow(G1[i],2.0); + } + } + double factor; + double ktemp = pSPARC->kB * pSPARC->thermos_T; + factor = pSPARC->MD_dt / 2.0 * (pSPARC->dof*ktemp*(log(pSPARC->S_NPT_NP) + 1) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP) - pSPARC->NPT_NP_qmass*pSPARC->Sv_NPT_NP; + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + if ((1.0 - factor*pSPARC->MD_dt/pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + exit(EXIT_FAILURE); + } + pSPARC->Sv_NPT_NP = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("Sv_NPT_NP in the 2nd half step is %12.9f\n", pSPARC->Sv_NPT_NP); + #endif +} + +/* + @ brief: update positions of particles, value of thermostat variable and barostat variables in the step +*/ +void updatePosition(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + int judge = 0; + // update value of thermostat variable S_NPT_NP + double Stemp = pSPARC->S_NPT_NP; + double Snew; + int timeIter = 0; + while (judge == 0) { + timeIter++; + Snew = pSPARC->S_NPT_NP + pSPARC->MD_dt / 2.0 * (pSPARC->S_NPT_NP + Stemp) * pSPARC->Sv_NPT_NP; + if (fabs(Snew - Stemp) < 1e-7) { + judge = 1; + } + Stemp = Snew; + if (timeIter > pSPARC->maxTimeIter) { + judge = 1; + if (rank == 0) + printf("Reminder: The value of thermostat variable S_NPT_NP does not converge in %d iterations.\n", pSPARC->maxTimeIter); + } + } + #ifdef DEBUG + if (rank == 0) + printf("Stemp is %12.9f\n", Stemp); + #endif + // update values of barostat variables G_NPT_NP + double Gtmp[3], Gnew[3], Gpig[3], GpigOld[3]; + int i; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + Gtmp[i] = pSPARC->G_NPT_NP[i]; + GpigOld[i] = pow(pSPARC->G_NPT_NP[i], 2.0) * pSPARC->Pm_NPT_NP[i]; + } + } + judge = 0; timeIter = 0; + while (judge == 0){ + timeIter++; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + Gpig[i] = pow(Gtmp[i], 2.0) * pSPARC->Pm_NPT_NP[i]; + Gnew[i] = pSPARC->G_NPT_NP[i] + pSPARC->MD_dt / 2.0 * (pSPARC->S_NPT_NP/(pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0))*GpigOld[i] + Stemp/(pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0))*Gpig[i]); + } + } + judge = 1; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + if (fabs(Gnew[i] - Gtmp[i]) > 1e-7) { + judge = 0; + } + Gtmp[i] = Gnew[i]; + } + } + if (timeIter > pSPARC->maxTimeIter) { + judge = 1; + if (rank == 0) + printf("Reminder: The barostat variables G_NPT_NP do not converge in %d iterations.\n", pSPARC->maxTimeIter); + } + } + double G3[3]; + for (i = 0; i < 3; i++) { + if (pSPARC->NPTscaleVecs[i] == 1) { + pSPARC->G_NPT_NP[i] = Gtmp[i]; + G3[i] = pow(Gtmp[i], 2.0) * pSPARC->Pm_NPT_NP[i]; + } + } + #ifdef DEBUG + if (rank == 0) { + printf("pSPARC->G_NPT_NP[0] is %12.9f\n", pSPARC->G_NPT_NP[0]); + printf("pSPARC->G_NPT_NP[1] is %12.9f\n", pSPARC->G_NPT_NP[1]); + printf("pSPARC->G_NPT_NP[2] is %12.9f\n", pSPARC->G_NPT_NP[2]); + } + #endif + // update side lengths of cells and velocities of them + double scalex = sqrt(pSPARC->G_NPT_NP[0]) / pSPARC->range_x; + pSPARC->range_x = sqrt(pSPARC->G_NPT_NP[0]); + double scaley = sqrt(pSPARC->G_NPT_NP[1]) / pSPARC->range_y; + pSPARC->range_y = sqrt(pSPARC->G_NPT_NP[1]); + double scalez = sqrt(pSPARC->G_NPT_NP[2]) / pSPARC->range_z; + pSPARC->range_z = sqrt(pSPARC->G_NPT_NP[2]); + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + if (pSPARC->NPTscaleVecs[0] == 1) + pSPARC->range_x_velo = G3[0] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_x; + else + pSPARC->range_x_velo = 0.0; + if (pSPARC->NPTscaleVecs[1] == 1) + pSPARC->range_y_velo = G3[1] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_y; + else + pSPARC->range_y_velo = 0.0; + if (pSPARC->NPTscaleVecs[2] == 1) + pSPARC->range_z_velo = G3[2] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_z; + else + pSPARC->range_z_velo = 0.0; + // update positions of particles, and restore the values of particle velocities + int count = 0; + int atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = (pSPARC->atom_pos[count * 3]) * scalex + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3]/Stemp); // + pSPARC->atom_pos[count * 3 + 1] = (pSPARC->atom_pos[count * 3 + 1]) * scaley + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 1]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 1]/Stemp); // + pSPARC->atom_pos[count * 3 + 2] = (pSPARC->atom_pos[count * 3 + 2]) * scalez + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 2]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 2]/Stemp); // + pSPARC->ion_vel[count * 3] /= Stemp; + pSPARC->ion_vel[count * 3 + 1] /= Stemp; + pSPARC->ion_vel[count * 3 + 2] /= Stemp; + count ++; + } + pSPARC->S_NPT_NP = Stemp; +} + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + else + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the qunatities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE/pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + // Compute Ionic stress/pressure + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; + int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(sizeof(double), 9); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":NPT_NP_Sv: %.15g\n", pSPARC->Sv_NPT_NP); // velocity of virtual thermal parameter + fprintf(mdout,":NPT_NP_Pm: %.15g %.15g %.15g\n", pSPARC->Pm_NPT_NP[0], pSPARC->Pm_NPT_NP[1], pSPARC->Pm_NPT_NP[2]); // velocity of virtual baro parameter + fprintf(mdout,":NPT_NP_S: %.15g\n", pSPARC->S_NPT_NP); // value of virtual thermal parameter + fprintf(mdout,":NPT_NP_range_x_velo: %.15g\n", pSPARC->range_x_velo); // velocity of virtual x baro parameter + fprintf(mdout,":NPT_NP_range_y_velo: %.15g\n", pSPARC->range_y_velo); // velocity of virtual y baro parameter + fprintf(mdout,":NPT_NP_range_z_velo: %.15g\n", pSPARC->range_z_velo); // velocity of virtual z baro parameter + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + // Print temperature + fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); + + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_Sv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->Sv_NPT_NP); + else if (strcmpi(str,":NPT_NP_S:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->S_NPT_NP); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":NPT_NP_range_x_velo:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->range_x_velo); + else if (strcmpi(str,":NPT_NP_range_y_velo:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->range_y_velo); + else if (strcmpi(str,":NPT_NP_range_z_velo:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->range_z_velo); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->Sv_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->S_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->Sv_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->S_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + diff --git a/src/initialization.c b/src/initialization.c index 18345b8f..a2ec5b61 100644 --- a/src/initialization.c +++ b/src/initialization.c @@ -836,7 +836,11 @@ void set_defaults(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } // default mass of thermo variables for NPT_NH. If MDMeth is this but one of qmass is 0, program will stop pSPARC_Input->NPT_NHbmass = 0.0; // default mass of baro variable for NPT_NH. If MDMeth is this but bmass is 0, program will stop pSPARC_Input->prtarget = 0.0; // default target pressure for NPT_NH. + pSPARC_Input->pr_external = 0.0; // default target pressure for NPT_NP and NPH. + for (int i = 0; i<6; ++i){ + pSPARC_Input->stress_external[i] = 0.0; // default target pressure for NPT_NP and NPH. + } pSPARC_Input->NPT_NP_qmass = 0.0; // default mass of thermo variables for NPT_NP. If MDMeth is this but qmass is 0, program will stop pSPARC_Input->NPT_NP_bmass = 0.0; // default mass of thermo variables for NPT_NP. If MDMeth is this but bmass is 0, program will stop @@ -4329,7 +4333,7 @@ void print_orthogonal_warning(SPARC_OBJ *pSPARC, FILE *output_fp) void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { SPARC_INPUT_OBJ sparc_input_tmp; - MPI_Datatype SPARC_types[N_MEMBR] = {MPI_INT, MPI_INT, MPI_INT, + MPI_Datatype SPARC_types[N_MEMBR] = {MPI_INT, MPI_INT, MPI_INT, /* int array */ MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, @@ -4353,10 +4357,10 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, - MPI_INT, MPI_INT, MPI_INT, MPI_INT, /* int array */ + MPI_INT, MPI_INT, MPI_INT, MPI_INT, /* int */ MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, - MPI_DOUBLE, MPI_DOUBLE, + MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, /* double array */ MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, @@ -4371,8 +4375,8 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, - MPI_DOUBLE, - MPI_CHAR, MPI_CHAR, MPI_CHAR, MPI_CHAR, MPI_CHAR, + MPI_DOUBLE, MPI_DOUBLE, /* double */ + MPI_CHAR, MPI_CHAR, MPI_CHAR, MPI_CHAR, MPI_CHAR, /* char */ MPI_CHAR, MPI_CHAR, MPI_CHAR, MPI_CHAR, MPI_CHAR}; int blens[N_MEMBR] = {3, 3, 7, /* int array */ 1, 1, 1, 1, 1, @@ -4400,7 +4404,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { 1, 1, 1, 1, 1, 1, 1, 1, 1, /* int */ 9, 3, L_QMASS, L_kpoint, L_kpoint, - L_kpoint, 6, /* double array */ + L_kpoint, 6, 6,/* double array */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -4414,7 +4418,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, /* double */ + 1, 1, 1, /* double */ 32, 32, 32, L_STRING, L_STRING, /* char */ L_STRING, L_STRING, L_STRING, L_STRING, L_STRING}; @@ -4554,6 +4558,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_Get_address(&sparc_input_tmp.kredx, addr + i++); MPI_Get_address(&sparc_input_tmp.kredy, addr + i++); MPI_Get_address(&sparc_input_tmp.kredz, addr + i++); + MPI_Get_address(&sparc_input_tmp.stress_external, addr + i++); MPI_Get_address(&sparc_input_tmp.stress_rel_scale, addr + i++); // double type @@ -4630,6 +4635,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_Get_address(&sparc_input_tmp.F_rel_scale, addr + i++); MPI_Get_address(&sparc_input_tmp.relaxPrTarget, addr + i++); + MPI_Get_address(&sparc_input_tmp.pr_external, addr + i++); // char type diff --git a/src/md.c b/src/md.c index 296d6f3f..fa3e017b 100644 --- a/src/md.c +++ b/src/md.c @@ -16,7 +16,7 @@ #ifdef USE_MKL #include #else - #include + #include #include #endif @@ -149,6 +149,8 @@ void main_MD(SPARC_OBJ *pSPARC) { NPT_NH(pSPARC); else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) NPT_NP(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPH(pSPARC); else{ if (!rank){ printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); @@ -319,9 +321,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { } } - //Calculate metric_tensor G, reciprocal metric tensor, angles between lattice vectors, rotation matrix - fetch_MD_cell_ingredients(pSPARC); - + pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i1 = 0; i1 < 6; i1++){ pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -344,18 +344,22 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { } if(strcmpi(pSPARC->MdMeth,"NPH")){ - pSPARC->NPT_NPH_qmass = 0 + pSPARC->NPT_NP_qmass = 0; if (!rank) { printf("Mass of thermostat variable is zero in NPH ensemble. If choosing MD_method as NPH with nonzero thermostat mass, it would be automatically set to zero at this point\n"); } } + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) pSPARC->thermos_Ti = pSPARC->ion_T; pSPARC->thermos_T = pSPARC->thermos_Ti; + fetch_MD_cell_ingredients(pSPARC, false); + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); } else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart @@ -367,9 +371,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); pSPARC->maxTimeIter = 30; - - fetch_MD_cell_ingredients(pSPARC); - + // pSPARC->thermos_Ti = pSPARC->elec_T; pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -387,9 +389,10 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; if(strcmpi(pSPARC->MdMeth,"NPH")){ - pSPARC->NPT_NPH_qmass = 0 + pSPARC->NPT_NP_qmass = 0; } + fetch_MD_cell_ingredients(pSPARC, false); Calculate_ionic_stress(pSPARC); } @@ -725,7 +728,7 @@ void Leapfrog_part2(SPARC_OBJ *pSPARC) { } } -} +} /** @@ -1081,7 +1084,7 @@ void PositionParticleCell(SPARC_OBJ *pSPARC) { count ++; } // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlog v * rescale); if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; @@ -1348,7 +1351,7 @@ void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. */ -void NPT_NP (SPARC_OBJ *pSPARC) { +void NPT_NP(SPARC_OBJ *pSPARC) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); @@ -1356,10 +1359,8 @@ void NPT_NP (SPARC_OBJ *pSPARC) { //NPT_NPH_main routine NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) elecDensExtrapolation(pSPARC); // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain @@ -1382,19 +1383,16 @@ The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." Physical Review B 55.14 (1997): 8733. */ -void NPH (SPARC_OBJ *pSPARC) { +void NPH(SPARC_OBJ *pSPARC) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - pSPARC->NPT_NP_qmass = 0; //NPT_NPH_main routine NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) elecDensExtrapolation(pSPARC); // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain @@ -1412,84 +1410,97 @@ void NPH (SPARC_OBJ *pSPARC) { /* Computes transpose of a matrix and adds it to the original matrix */ -void transpose_and_add(double *matrix1, int flag){ - - //Pure transpose - if (flag==0){ - double tmp; - // Swap (0,1) with (1,0) - tmp = matrix1[1]; matrix1[1] = matrix1[3]; matrix1[3] = tmp; - // Swap (0,2) with (2,0) - tmp = matrix1[2]; matrix1[2] = matrix1[6]; matrix1[6] = tmp; - // Swap (1,2) with (2,1) - tmp = matrix1[5]; matrix1[5] = matrix1[7]; matrix1[7] = tmp; - } - +void transpose_and_add(double *matrix1){ //performs matrix1 = matrix1 + transpose(matrix1) - else if (flag==1){ - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; - } + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; } /* Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix */ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC){ - +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + double old_cell[9]; double new_cell[9]; - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row, col; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row, col; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + } // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) new_cell[0] = sqrt(pSPARC->metric_tensor[0]); new_cell[1] = 0; new_cell[2] = 0; - new_cell[3] = pSPARC->metric_tensor[3]/sqrt(metric_tensor[0]); - new_cell[4] = sqrt(pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3]*pSPARC->metric_tensor[3])/pSPARC->metric_tensor[0]; + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); new_cell[5] = 0; - new_cell[6] = pSPARC->metric_tensor[6]/sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = (pSPARC->metric_tensor[0]*pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3]*pSPARC->metric_tensor[6])/sqrt(pSPARC->metric_tensor[0]*pSPARC->metric_tensor[0]*pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0]*pSPARC->metric_tensor[3]*pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]) + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt(pSPARC->metric_tensor[0]); + pSPARC->range_y = sqrt(pSPARC->metric_tensor[4]); + pSPARC->range_z = sqrt(pSPARC->metric_tensor[8]); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat(pSPARC); + + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + + + } + //Update reciprocal lattice vectors, reciprocal metric tensor for (int i = 0; i<9; i++){ - old_cell[i] = pSPARC->full_lattice[i] + old_cell[i] = pSPARC->full_lattice[i]; } - // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = cblas_ddot(3,&lattice1[3], 1.0, &lattice1[6],1.0 )/(pSPARC->range_y*pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = cblas_ddot(3,&lattice1[0], 1.0, &lattice1[6],1.0 )/(pSPARC->range_x*pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = cblas_ddot(3,&lattice1[0], 1.0, &lattice1[3],1.0 )/(pSPARC->range_x*pSPARC->range_y); // cos_gamma - + // Calculate the inverse of lattice-vector - double U[9], S[3], VT[9], superb[2], temp_mat[9] - double S_inv[9] = {0} + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3,3,old_cell,3,S,U,3,VT,3,superb); + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); // First compute S^{-1} for (int i = 0; i < 3; i++) { @@ -1497,105 +1508,118 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC){ } // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since lattice1 is rowMajor, reciprocal_lattice1 is columnMajor - // i.e. the reciprocal lattice vectors (of lattice1) are stored column-wise + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPRAC->reciprocal_lattice, 3); - - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; - cblas_dgemm(CblasRowMajor, CblasTrans, CblasTrans, 3, 3, 3, 1.0, pSPRAC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); // Now computing reciprocal metric tensor, - cblas_dgemm(cblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPRAC->reciprocal_lattice, 3, pSPRAC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - - //TODO: Update cell volume - //TODO: Update Jacbdet - //TODO: Update LatVec - //TODO: Update LatUvec + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - //Computing velocity of lattice vectors - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int iu1 = 0; iu1 < 9; iu1++){ - temp_mat_3[iu1] = pSPARC->Pm_metric_tensor; + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } } - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + //If updating the cell, then also calculate the velocity of cell lattice vectors + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - for (int iu1 = 0; iu1 < 9; iu1++){ - temp_mat_2[iu1] = 0.0; - pSPARC->lattice_avg_velo[iu1] = 0.0; - } + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - temp_mat_2[0] = temp_mat_3[0] / (2.0 * new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->rotation_matrix , 3, temp_mat_2, 3, 0.0, pSPARC->lattice_avg_velo, 3); + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } } + void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - double vec1[3]; int count = 0; pSPARC->KE = 0.0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - cblas_dgemv(CblasRowMajor, CblasNoTrans,3,3,1.0,pSPARC->reciprocal_metric_tensor,3,&pSPARC->Pm_ion[count*3],1,0.0,vec1,1); - pSPARC->KE += cblas_ddot(3,vec1,1, &pSPARC->Pm_ion[count*3],1)/pSPARC->Mass[ityp]; + int ityp, atm; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); count ++; } } - pSPARC->KE = 0.5*pSPARC->KE/(pSPARC->SNOSE[0]*pSPARC->SNOSE[0]); - double temperature = 2.0*pSPARC->KE/(pSPARC->dof*pSPARC->kB) + pSPARC->KE = pSPARC->KE / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]); + double temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); } -void Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ - double kinetic_stress[9] = {0.0}; +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + int count = 0; for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count*3] = (pSPARC->reciprocal_metric_tensor[0] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[1] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[2] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count*3+1] = (pSPARC->reciprocal_metric_tensor[3] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[4] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[5] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count*3+2] = (pSPARC->reciprocal_metric_tensor[6] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[7] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[8] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; - + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; } } - int count = 0; + count = 0; for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3]; - kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+1]; - kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+2]; - kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+1]; - kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+2]; + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; count++; } } - kinetic_stress[3] = kinetic_stress[1]; - kinetic_stress[6] = kinetic_stress[2]; - kinetic_stress[7] = kinetic_stress[5]; + free(ion_vel_fractional); + + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), kinetic_stress, 1); + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - for (int its1 = 0; its1<9; its1++){ - pSPARC->total_internal_stress[its1] = ( kinetic_stress[its1] - pSPARC->internal_stress - pSPARC->constraint_stress) + for (int i = 0; i < 9; i++){ + pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i]) } cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); @@ -1604,59 +1628,39 @@ void Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_O } -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC){ + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - - pSPARC->ionic_forces_fractional = (double *)malloc(pSPARC->n_atom*3 * sizeof(double) ); //Initialize some useful constants - double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; double baro_const3 = 1.0 / baro_const1; + double ktemp; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10a)----------------------------------// - // Calculating momentum of ions - int ityp, atm; - int count = 0; - cblas_dscal(pSPARC->n_atom*3,pSPARC->SNOSE[2],pSPARC->ion_vel,1); - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - cblas_dgemv(CblasRowMajor,CblasNoTrans,3,3,pSPARC->Mass[ityp],pSPARC->metric_tensor,3,&pSPARC->ion_vel[count*3],1,0.0,&pSPARC->Pm_ion[count*3],1) - count ++; - } - } + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// // Calculating kinetic energy of ions - Calculate_Ionic_particles_Kinetic_energy(pSPARC); + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper // Calculating barostat energies cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor,1); + transpose_and_add(pSPARC->Pm_metric_tensor); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(pSPARC->n_atom*3,baro_const2,pSPARC->Pm_metric_tensor,1); + cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) @@ -1664,17 +1668,45 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9,temp_mat_a, 1, temp_mat_b,1);//Kinetic - pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell; //Potential + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b,1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5*cblas_ddot(9,pSPARC->external_stress_lattice,1,pSPARC->metric_tensor,1) + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - double sumAllHamilTerms = pSPARC->Etot; + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp; + int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + //Initialize some useful constants + double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + + double sumAllHamilTerms = pSPARC->Etot;//Potential; Term 2 in Eqn.10 in Hernandez paper sumAllHamilTerms += pSPARC->KE + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper #ifdef DEBUG if (rank == 0) { printf("\n"); @@ -1690,65 +1722,76 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); } #endif - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10a)----------------------------------// + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa; + double Sa = 0.0; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) if (pSPARC->NPT_NP_qmass > 0){ ktemp = pSPARC->kB * pSPARC->thermos_T; Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; - + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif // Update the kinetic energy of the thermostat pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper } - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress[4] = pSPARC->stress[3]; internal_stress[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress[2] = pSPARC->stress[2]; internal_stress[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress[6] = pSPARC->stress[2]; internal_stress[7] = pSPARC->stress[4]; + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: so reciprocal lattice vectors are columns) - for (int itma1 = 0; itma1<9; itma1++){ - temp_mat_a[itma1] = pSPARC->reciprocal_lattice[itma1]; + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) + for (int i = 0; i < 9; i++){ + temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 + } + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + } + + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3,pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - for (int ix1 = 0; ix1<9; ix1++){ - temp_Pm_mat[ix1] = pSPARC->Pm_metric_tensor[ix1]; + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; } // Eqn. 18h Hernandez paper - for (int ih18 = 0; ih18<9; ih18++){ - temp_mat[ih18] = internal_stress_fractional[ih18] - pSPARC->kinetic_stress[ih18] + temp_mat_b[ih18]; - temp_mat[ih18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ih18] + 0.5*pSPARC->external_stress_lattice[ih18]; - pSPARC->Pm_metric_tensor[ih18] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ih18]; + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } if (pSPARC->NPT_NP_ANGLES == 0){ compute_constraint_stress(pSPARC); } - for (int ih18 = 0; ih18<9; ih18++){ - temp_mat[ih18] = internal_stress_fractional[ih18] + pSPARC->constraint_stress[ih18] - pSPARC->kinetic_stress[ih18] + temp_mat_b[ih18]; - temp_mat[ih18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ih18] + 0.5*pSPARC->external_stress_lattice[ih18]; - pSPARC->Pm_metric_tensor[ih18] = temp_Pm_mat[ih18] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ih18]; + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } if (ISIF == 10){ @@ -1760,38 +1803,43 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ } if (ISIF == 11){ - pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9,temp_mat_a, 1, temp_mat_b,1);//Kinetic + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds to Eqn. 18i in Hernandez paper - double thermo_const0 = pSPARC->MD_dt*pSPARC->SNOSE[0] / 2.0; - for(int natm1 = 0; natm1 < pSPARC->n_atom; natm1++){ - pSPARC->ionic_forces_fractional[natm1*3] = (pSPARC->full_lattice[0] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[1] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[2] * pSPARC->forces[natm1*3+2]); - pSPARC->ionic_forces_fractional[natm1*3+1] = (pSPARC->full_lattice[3] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[4] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[5] * pSPARC->forces[natm1*3+2]); - pSPARC->ionic_forces_fractional[natm1*3+2] = (pSPARC->full_lattice[6] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[7] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[8] * pSPARC->forces[natm1*3+2]); - - pSPARC->Pm_ion[natm1*3] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3]; - pSPARC->Pm_ion[natm1*3+1] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+1]; - pSPARC->Pm_ion[natm1*3+2] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+2]; + cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } } //Update the kinetic energy of the Ionic particles Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Now write Intenal pressure, external pressure to a file @@ -1800,7 +1848,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ //Calculate/Update total energy (Hamiltonian) sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - double constant_of_motion = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); // Calculate the Hamiltonian (constant of motion) //Optionall write all individual energy contributions to the Hamiltonian to an output file @@ -1809,14 +1857,18 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ // Now we update/Step-up the momenta of the Ionic particles by dt/2 // This setup corresponds to Eqn. 18a in Hernandez paper - for(int natm1 = 0; natm1 < pSPARC->n_atom; natm1++){ - pSPARC->Pm_ion[natm1*3] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3]; - pSPARC->Pm_ion[natm1*3+1] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+1]; - pSPARC->Pm_ion[natm1*3+2] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+2]; + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } } //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Update the kinetic energy of the Ionic particles Calculate_Ionic_particles_Kinetic_energy(pSPARC); @@ -1825,7 +1877,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ // Now we update/Step-up the momenta of the barostat by dt/2 // This setup corresponds to Eqn. 18b in the Hernandez paper // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC); + Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); //Now impose the constraints on it if (ISIF == 10){ @@ -1841,14 +1893,17 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ pSPARC->Pm_metric_tensor[4] = 0; } + //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints + // SPARC code was doing both these steps, reference code does not seem to do + // Now we update/Step-up the momenta of the thermostat by dt/2 // This setup corresponds to Eqn. 18c in the Hernandez paper // Skip this step if doing NPH ensemble if (pSPARC->NPT_NP_qmass > 0){ double factor; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * (log(pSPARC->SNOSE[0])+1) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + ktemp = pSPARC->kB * pSPARC->thermos_T; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; #ifdef DEBUG if (rank == 0) @@ -1863,21 +1918,19 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); #ifdef DEBUG if (rank == 0) - printf("Sv_NPT_NP in the 2nd half step is %12.9f\n", pSPARC->Sv_NPT_NP); + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); #endif } // Now we update/Step-up the Position of the thermostat by dt/2 // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new; double S_temp; + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT ensemble - S_temp = pSPARC->SNOSE[0]; - + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) while (1) { S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp-S_new) < 1e-7) { + if (fabs(S_temp - S_new) < 1e-7) { break; } S_temp = S_new; @@ -1885,8 +1938,8 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ //it iteration count exceeds max iteration counts, exit if (TimeIter > pSPARC->maxTimeIter){ for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], - new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); + printf("%15.7f %15.7f %15.7f\n",S_new[row * 3 + 0], + S_new[row *3 + 1], S_new[row * 3 + 2]); printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); exit(1); } @@ -1903,29 +1956,67 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); + + //Before updating cell parameters, compute atom positions in fractional coordinates + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); + count++; + } + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC); + fetch_MD_cell_ingredients(pSPARC, true); + + //Update the Kinetic energy of the barostat based on new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / pSPARC->volumeCell / pSPARC->volumeCell; //Kinetic + + //Update the Potential energy of the barostat based on new metric tensor + pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); + count++; + } + free(atom_pos_fractional); //Update atomic positions and restore ionic velocities - int count = 0; - int atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = (pSPARC->atom_pos[count * 3]) * scalex + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3]/S_new); // - pSPARC->atom_pos[count * 3 + 1] = (pSPARC->atom_pos[count * 3 + 1]) * scaley + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 1]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 1]/S_new); // - pSPARC->atom_pos[count * 3 + 2] = (pSPARC->atom_pos[count * 3 + 2]) * scalez + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 2]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 2]/S_new); // + count = 0; + for(int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_new ); // + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_new ); // + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_new ); // pSPARC->ion_vel[count * 3] /= pSPARC->SNOSE[0]; pSPARC->ion_vel[count * 3 + 1] /= pSPARC->SNOSE[0]; pSPARC->ion_vel[count * 3 + 2] /= pSPARC->SNOSE[0]; count ++; } + //Update kinetic energy and kinetic stress based on new S + pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + } + + // Update SNOSE[0] to S_new if (pSPARC->NPT_NP_qmass > 0){ pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; pSPARC->SNOSE[0] = S_new; @@ -1933,7 +2024,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - + } @@ -2002,15 +2093,15 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ constraint_velocity[6] = constraint_velocity[2]; constraint_velocity[7] = constraint_velocity[5]; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3,constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0/baro_const4, gpi, 3,pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0/baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); // Calculating constraint stress - for (int intcs1 = 0; intcs1<9; intcs1++){ - pSPARC->constraint_stress[intcs1] = thermo_const1 * (pSPARC->Pm_metric_tensor[intcs1] - gpig[intcs1]); - pSPARC->Pm_metric_tensor[intcs1] = gpig[intcs1]; + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; } } @@ -2030,32 +2121,32 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do double gpi[9]; double gpig[9]; double gpig_old[9]; double temp_metric_tensor[9]; double new_metric_tensor[9]; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - for (int mtt1 = 0; mtt1 < 9; mtt1++){ - temp_metric_tensor[mtt1] = pSPARC->metric_tensor[mtt1]; - gpig_old[mtt1] = gpig[mtt1]; + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; } while (1){ - det_temp_metric_tensor = temp_metric_tensor[0] * (temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * (temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * (temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,temp_metric_tensor, 3, 0.0, gpig, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - for (int mtn = 0; mtn < 9; mtn++){ - new_metric_tensor[mtn] = pSPARC->metric_tensor[mtn] + baro_const6 * gpig_old[mtn] + baro_const7 * gpig[mtn]; + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; } converged = true; - for (int ic1 = 0; ic1 < 9; ic1++){ - if ( fabs(new_metric_tensor[ic1] - temp_metric_tensor[ic1]) > tolerance ){ + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ converged = false; break; } @@ -2065,21 +2156,24 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do break; } else{ cblas_dscal(9, 0.5 , new_metric_tensor, 1); - temp_metric_tensor = transpose_and_add(new_metric_tensor); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } } TimeIter++; //it iteration count exceeds max iteration counts, exit if (TimeIter > pSPARC->maxTimeIter){ for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row][0], - new_metric_tensor[row][1], new_metric_tensor[row][2]); + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); exit(1); } } - if (ISIF == 7){ + if (ISIF >= 7){ if (ISIF == 8){ new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; new_metric_tensor[4] = new_metric_tensor[0]; @@ -2103,24 +2197,33 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do new_metric_tensor[6] = new_metric_tensor[2]; new_metric_tensor[7] = new_metric_tensor[5]; - for (int mtt1 = 0; mtt1 < 9; mtt1++){ - temp_metric_tensor[mtt1] = new_metric_tensor[mtt1]; + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; } } - for (int mt1 = 0; mt1 < 9; mt1++){ - pSPARC->metric_tensor[mt1] = temp_metric_tensor[mt1]; + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } } + #endif + } -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ //Initialize some useful constants bool converged; // determine whether the iteration converges or not int TimeIter = 0; // current iteration count - const double tolerance = 1e-12; // tolerance criterion for checking convergence + const double tolerance = 1e-7; // tolerance criterion for checking convergence double baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); double baro_const3 = 0.5 / baro_const0; double baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; @@ -2131,19 +2234,19 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - for (int itpmt1 = 0; itpmt1 < 9; itpmt1++){ - temp_Pm_metric_tensor[itpmt1] = pSPARC->Pm_metric_tensor[itpmt1]; + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; } // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) while (1){ cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, - pSPARC->metric_tensor[0][0], 3, + pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, - matrix_1, 3, + temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); @@ -2153,17 +2256,17 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - pSPARC->Kbaro = baro_const5 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); // Eqn. 18b Hernandez paper - for (int ib18 = 0; ib18<9; ib18++){ - temp_mat[ib18] = internal_stress_fractional[ib18] - pSPARC->kinetic_stress[ib18] + temp_mat_2[ib18]; - temp_mat[ib18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ib18] + 0.5*pSPARC->external_stress_lattice[ib18]; - new_Pm_metric_tensor[ib18] = pSPARC->Pm_metric_tensor[ib18] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ib18]; + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); //Check convergence converged = true; @@ -2178,8 +2281,8 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ if (converged){ break; } else{ - for (int ic1 = 0; ic1 < 9; ic1++){ - temp_Pm_metric_tensor[ic1] = new_Pm_metric_tensor[ic1]; + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; } } @@ -2187,8 +2290,8 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ //it iteration count exceeds max iteration counts, exit if (TimeIter > pSPARC->maxTimeIter){ for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], - new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); exit(1); } @@ -2196,290 +2299,15 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ } // As converged, update the metric tensor momenta - for (int c11 = 0; c11 < 9; c11++){ - pSPARC->Pm_metric_tensor[c11] = temp_Pm_metric_tensor[c11]; - } -} - - - - -void updateMomentum_FirstHalf(SPARC_OBJ *pSPARC) { - double ktemp; - double Ga1[3]; - double B[3]; - double Ga3[3]; - double PmA[3]; - - - - - - // update momentum of barostat variables in a half step - for (int i = 0; i < 3; i++){ - if (pSPARC->NPTscaleVecs[i] == 1) { - Ga1[i] = innerControlStress[i] * pSPARC->volumeCell / 2.0 / pSPARC->G_NPT_NP[i]; - B[i] = 1.0 / (pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) * pow(pSPARC->Pm_NPT_NP[i],2.0) * pSPARC->G_NPT_NP[i]; - Ga3[i] = (pSPARC->prtarget * pSPARC->volumeCell / 2.0 - pSPARC->Kbaro) / pSPARC->G_NPT_NP[i]; - PmA[i] = Ga1[i] + B[i] + Ga3[i]; - pSPARC->Pm_NPT_NP[i] -= pSPARC->MD_dt * pSPARC->S_NPT_NP / 2.0 * PmA[i]; - #ifdef DEBUG - if (rank == 0){ - // printf("pSPARC->pres is %12.9f, pSPARC->pres_i is %12.9f, pSPARC->volumeCell is %12.9f, pSPARC->G_NPT_NP[%d] is %12.9f\n", pSPARC->pres, pSPARC->pres_i, pSPARC->volumeCell, i, pSPARC->G_NPT_NP[i]); - printf("PmA[%d] is %12.9f\n", i, PmA[i]); - printf("pSPARC->Pm_NPT_NP[%d] in 1st half step is %12.9f\n", i, pSPARC->Pm_NPT_NP[i]); - } - #endif - } - } - // update momentum/mass of particles (reminder: not velocity!) in a step - int ityp, atm; - int count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] = pSPARC->ion_vel[count * 3] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3 + 2]; - // for now they are not velocity! - count ++; - } - } -} - -/* - @ brief: update momentum of thermostat and barostat variables in the second half step -*/ -void updateMomentum_SecondHalf(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double PmTmp[3], PmNew[3]; - int i; - for (i = 0; i < 3; i++){ - PmTmp[i] = pSPARC->Pm_NPT_NP[i]; - } - // update momentum of barostat variables in the second half time step - int judge = 0; - int timeIter = 0; - double G1[3], Gatmp1[3], Gatmp2[3], Gatmp3[3], PmAtmp[3]; - double KbaroTmp = 0; - - double diagElecStress[3], innerControlStress[3]; - diagElecStress[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; - diagElecStress[1] = pSPARC->stress[3] - pSPARC->stress_i[3]; - diagElecStress[2] = pSPARC->stress[5] - pSPARC->stress_i[5]; - // innerControlStress is used for adding confinements on the scale of lattice vectors, such as |a|=|b|. - innerControlStress[0] = diagElecStress[0]; - innerControlStress[1] = diagElecStress[1]; - innerControlStress[2] = diagElecStress[2]; - if (pSPARC->NPTconstraintFlag == 1) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[1]) / 2; - innerControlStress[1] = innerControlStress[0]; - } else if (pSPARC->NPTconstraintFlag == 2) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[2]) / 2; - innerControlStress[2] = innerControlStress[0]; - } else if (pSPARC->NPTconstraintFlag == 3) { - innerControlStress[1] = (diagElecStress[1] + diagElecStress[2]) / 2; - innerControlStress[2] = innerControlStress[1]; - } else if (pSPARC->NPTconstraintFlag == 4) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[1] + diagElecStress[2]) / 3; - innerControlStress[1] = innerControlStress[0]; - innerControlStress[2] = innerControlStress[0]; - } - - while (judge == 0) { - timeIter++; - KbaroTmp = 0; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - G1[i] = 1 / (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) * PmTmp[i] * pSPARC->G_NPT_NP[i]; - KbaroTmp += (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) / 2 * pow(G1[i],2.0); - } - } - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - Gatmp1[i] = innerControlStress[i] * pSPARC->volumeCell / 2.0 / pSPARC->G_NPT_NP[i]; - Gatmp2[i] = G1[i] * PmTmp[i]; - Gatmp3[i] = (pSPARC->prtarget * pSPARC->volumeCell / 2.0 - KbaroTmp) / pSPARC->G_NPT_NP[i]; - PmAtmp[i] = Gatmp1[i] + Gatmp2[i] + Gatmp3[i]; - PmNew[i] = pSPARC->Pm_NPT_NP[i] - pSPARC->MD_dt / 2.0 * pSPARC->S_NPT_NP * PmAtmp[i]; - } - } - judge = 1; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - if (fabs(PmNew[i] - PmTmp[i]) > 1e-7){ - judge = 0; - } - PmTmp[i] = PmNew[i]; - } - } - if (timeIter > pSPARC->maxTimeIter){ - judge = 1; - if (rank == 0) - printf("Reminder: The barostat momentum Pm_NPT_NP does not converge in %d timesteps.\n", pSPARC->maxTimeIter); - } - } - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - pSPARC->Pm_NPT_NP[i] = PmTmp[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_NPT_NP[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_NPT_NP[i]); - #endif - } - } - - // update thermostat velocity in the second half time step - pSPARC->KE = 0.0; - int ityp, atm; - int count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - pSPARC->KE /= pow(pSPARC->S_NPT_NP, 2.0); // from momentum/mass to true velocity - pSPARC->Kbaro = 0.0; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - G1[i] = 1.0 / (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) * PmTmp[i] * pSPARC->G_NPT_NP[i]; - pSPARC->Kbaro += (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) / 2.0 * pow(G1[i],2.0); - } - } - double factor; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - factor = pSPARC->MD_dt / 2.0 * (pSPARC->dof*ktemp*(log(pSPARC->S_NPT_NP) + 1) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP) - pSPARC->NPT_NP_qmass*pSPARC->Sv_NPT_NP; - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor*pSPARC->MD_dt/pSPARC->NPT_NP_qmass) < 0.0){ + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG if (rank == 0) - printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - exit(EXIT_FAILURE); + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif } - pSPARC->Sv_NPT_NP = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("Sv_NPT_NP in the 2nd half step is %12.9f\n", pSPARC->Sv_NPT_NP); - #endif } -/* - @ brief: update positions of particles, value of thermostat variable and barostat variables in the step -*/ -void updatePosition(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - int judge = 0; - // update value of thermostat variable S_NPT_NP - double Stemp = pSPARC->S_NPT_NP; - double Snew; - int timeIter = 0; - while (judge == 0) { - timeIter++; - Snew = pSPARC->S_NPT_NP + pSPARC->MD_dt / 2.0 * (pSPARC->S_NPT_NP + Stemp) * pSPARC->Sv_NPT_NP; - if (fabs(Snew - Stemp) < 1e-7) { - judge = 1; - } - Stemp = Snew; - if (timeIter > pSPARC->maxTimeIter) { - judge = 1; - if (rank == 0) - printf("Reminder: The value of thermostat variable S_NPT_NP does not converge in %d iterations.\n", pSPARC->maxTimeIter); - } - } - #ifdef DEBUG - if (rank == 0) - printf("Stemp is %12.9f\n", Stemp); - #endif - // update values of barostat variables G_NPT_NP - double Gtmp[3], Gnew[3], Gpig[3], GpigOld[3]; - int i; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - Gtmp[i] = pSPARC->G_NPT_NP[i]; - GpigOld[i] = pow(pSPARC->G_NPT_NP[i], 2.0) * pSPARC->Pm_NPT_NP[i]; - } - } - judge = 0; timeIter = 0; - while (judge == 0){ - timeIter++; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - Gpig[i] = pow(Gtmp[i], 2.0) * pSPARC->Pm_NPT_NP[i]; - Gnew[i] = pSPARC->G_NPT_NP[i] + pSPARC->MD_dt / 2.0 * (pSPARC->S_NPT_NP/(pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0))*GpigOld[i] + Stemp/(pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0))*Gpig[i]); - } - } - judge = 1; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - if (fabs(Gnew[i] - Gtmp[i]) > 1e-7) { - judge = 0; - } - Gtmp[i] = Gnew[i]; - } - } - if (timeIter > pSPARC->maxTimeIter) { - judge = 1; - if (rank == 0) - printf("Reminder: The barostat variables G_NPT_NP do not converge in %d iterations.\n", pSPARC->maxTimeIter); - } - } - double G3[3]; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - pSPARC->G_NPT_NP[i] = Gtmp[i]; - G3[i] = pow(Gtmp[i], 2.0) * pSPARC->Pm_NPT_NP[i]; - } - } - #ifdef DEBUG - if (rank == 0) { - printf("pSPARC->G_NPT_NP[0] is %12.9f\n", pSPARC->G_NPT_NP[0]); - printf("pSPARC->G_NPT_NP[1] is %12.9f\n", pSPARC->G_NPT_NP[1]); - printf("pSPARC->G_NPT_NP[2] is %12.9f\n", pSPARC->G_NPT_NP[2]); - } - #endif - // update side lengths of cells and velocities of them - double scalex = sqrt(pSPARC->G_NPT_NP[0]) / pSPARC->range_x; - pSPARC->range_x = sqrt(pSPARC->G_NPT_NP[0]); - double scaley = sqrt(pSPARC->G_NPT_NP[1]) / pSPARC->range_y; - pSPARC->range_y = sqrt(pSPARC->G_NPT_NP[1]); - double scalez = sqrt(pSPARC->G_NPT_NP[2]) / pSPARC->range_z; - pSPARC->range_z = sqrt(pSPARC->G_NPT_NP[2]); - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - if (pSPARC->NPTscaleVecs[0] == 1) - pSPARC->range_x_velo = G3[0] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_x; - else - pSPARC->range_x_velo = 0.0; - if (pSPARC->NPTscaleVecs[1] == 1) - pSPARC->range_y_velo = G3[1] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_y; - else - pSPARC->range_y_velo = 0.0; - if (pSPARC->NPTscaleVecs[2] == 1) - pSPARC->range_z_velo = G3[2] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_z; - else - pSPARC->range_z_velo = 0.0; - // update positions of particles, and restore the values of particle velocities - int count = 0; - int atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = (pSPARC->atom_pos[count * 3]) * scalex + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3]/Stemp); // - pSPARC->atom_pos[count * 3 + 1] = (pSPARC->atom_pos[count * 3 + 1]) * scaley + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 1]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 1]/Stemp); // - pSPARC->atom_pos[count * 3 + 2] = (pSPARC->atom_pos[count * 3 + 2]) * scalez + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 2]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 2]/Stemp); // - pSPARC->ion_vel[count * 3] /= Stemp; - pSPARC->ion_vel[count * 3 + 1] /= Stemp; - pSPARC->ion_vel[count * 3 + 2] /= Stemp; - count ++; - } - pSPARC->S_NPT_NP = Stemp; -} /** * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c @@ -2585,7 +2413,7 @@ void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { exit(EXIT_FAILURE); } } - } + } } else if(BC == 0){ for(atm = 0; atm < pSPARC->n_atom; atm++){ coord_temp = *(coord+3*atm+dir); @@ -2793,7 +2621,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md," %18.10E\n",avgvel[atm]); fprintf(output_md,":MAXV:\n"); for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); + fprintf(output_md," %18.10E\n",maxvel[atm]); #endif fprintf(output_md,":MIND:\n"); char elemType1[8], elemType2[8]; @@ -2941,7 +2769,7 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { // Wrap into [-0.5, 0.5) frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); + frac[1] -= round(frac[1]); frac[2] -= round(frac[2]); // dr_pbc = lattice * frac @@ -3149,7 +2977,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); - } + } else { l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); } @@ -3297,7 +3125,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { pSPARC->range_z = nowRange_z; } else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + fscanf(rst_fp,"%lf", &pSPARC->thermos_T i); else if (strcmpi(str,":TARGET_PRESSURE:") == 0) fscanf(rst_fp,"%lf", &pSPARC->prtarget); else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) @@ -3433,3 +3261,4 @@ void Rename_restart(SPARC_OBJ *pSPARC) { rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); } + \ No newline at end of file From 866fbed50a2560644865de9763640c5e4c1134fd Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 24 Mar 2026 14:23:18 -0400 Subject: [PATCH 07/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/initialization.c | 5 ++-- src/md.c | 2 +- src/readfiles.c | 62 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/initialization.c b/src/initialization.c index a2ec5b61..88c71de1 100644 --- a/src/initialization.c +++ b/src/initialization.c @@ -830,16 +830,17 @@ void set_defaults(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { pSPARC_Input->NPTscaleVecs[1] = 1; pSPARC_Input->NPTscaleVecs[2] = 1; // default lattice vectors to be rescaled in NPT pSPARC_Input->NPTconstraintFlag = 0; // confinement on side length of cell. none: no length confinement (default) + pSPARC_Input->NPT_NPH_ANGLES = 0; // default: no change in angles during NPT_NP or NPH ensemble pSPARC_Input->NPT_NHnnos = 0; // default amount of thermo variable for NPT_NH. If MDMeth is this but nnos is 0, program will stop for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < L_QMASS; subscript_NPTNH_qmass++){ pSPARC_Input->NPT_NHqmass[subscript_NPTNH_qmass] = 0.0; } // default mass of thermo variables for NPT_NH. If MDMeth is this but one of qmass is 0, program will stop pSPARC_Input->NPT_NHbmass = 0.0; // default mass of baro variable for NPT_NH. If MDMeth is this but bmass is 0, program will stop pSPARC_Input->prtarget = 0.0; // default target pressure for NPT_NH. - pSPARC_Input->pr_external = 0.0; // default target pressure for NPT_NP and NPH. + pSPARC_Input->pr_external = 0.0; // default externally applied hydrostatic pressure for NPT_NP and NPH. for (int i = 0; i<6; ++i){ - pSPARC_Input->stress_external[i] = 0.0; // default target pressure for NPT_NP and NPH. + pSPARC_Input->stress_external[i] = 0.0; // default externally applied anisotropic stress for NPT_NP and NPH. } pSPARC_Input->NPT_NP_qmass = 0.0; // default mass of thermo variables for NPT_NP. If MDMeth is this but qmass is 0, program will stop pSPARC_Input->NPT_NP_bmass = 0.0; // default mass of thermo variables for NPT_NP. If MDMeth is this but bmass is 0, program will stop diff --git a/src/md.c b/src/md.c index fa3e017b..6c49472e 100644 --- a/src/md.c +++ b/src/md.c @@ -1783,7 +1783,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } - if (pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPT_NP_NPH_ANGLES == 0){ compute_constraint_stress(pSPARC); } diff --git a/src/readfiles.c b/src/readfiles.c index 6b989d85..ea217489 100644 --- a/src/readfiles.c +++ b/src/readfiles.c @@ -777,6 +777,63 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { exit(EXIT_FAILURE); } fscanf(input_fp, "%*[^\n]\n"); + } else if (strcmpi(str,"NPT_NP_ANGLES:") == 0){ + fscanf(input_fp,"%d",&pSPARC_Input->NPT_NP_angles); + fscanf(input_fp, "%*[^\n]\n"); + + if (pSPARC_Input->NPTscaleVecs[0] == 0 || pSPARC_Input->NPTscaleVecs[1] == 0 || pSPARC_Input->NPTscaleVecs[2] == 0 && pSPARC_Input->NPTconstraintFlag == 0){ + printf("Angle changing is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints imposed on them.\n"); + printf("To allow Angle changing, input NPT_NP_ANGLES: 1, while simultaneously NPT_SCALE_VECS: 1 2 3 and omit/skip input of NPT_SCALE_CONSTRAINTS (so default: none will be triggered).\n"); + exit(EXIT_FAILURE); + } + } else if (strcmpi(str,"NPH_SCALE_VECS:") == 0) { + int dir[3] = {0, 0, 0}; + pSPARC_Input->NPHscaleVecs[0] = 0; pSPARC_Input->NPHscaleVecs[1] = 0; pSPARC_Input->NPHscaleVecs[2] = 0; + int scanfResult; + scanfResult = fscanf(input_fp,"%d %d %d\n",&dir[0], &dir[1], &dir[2]); + if (scanfResult == -1) { + scanfResult = fscanf(input_fp,"%d %d\n",&dir[0], &dir[1]); + } + if (scanfResult == -1) { + scanfResult = fscanf(input_fp,"%d\n",&dir[0]); + } + if (scanfResult == -1) { + printf("To correctly input NPH_SCALE_VECS, please do not add space or other characters between number and newline.\n"); + printf("input as NPH_SCALE_VECS: 1 2 3\n"); + exit(EXIT_FAILURE); + } + for (int i = 0; i < 3; i++) { + if (dir[i] > 0) pSPARC_Input->NPHscaleVecs[dir[i] - 1] = 1; + } + // fscanf(input_fp, "%*[^\n]\n"); + } else if (strcmpi(str,"NPH_SCALE_CONSTRAINTS:") == 0) { + fscanf(input_fp,"%s",temp); + if (strcmpi(temp,"none") == 0) { + pSPARC_Input->NPHconstraintFlag = 0; + } else if ((strcmpi(temp, "12") == 0) || (strcmpi(temp, "21") == 0)) { + pSPARC_Input->NPHconstraintFlag = 1; + } else if ((strcmpi(temp, "13") == 0) || (strcmpi(temp, "31") == 0)) { + pSPARC_Input->NPHconstraintFlag = 2; + } else if ((strcmpi(temp, "23") == 0) || (strcmpi(temp, "32") == 0)) { + pSPARC_Input->NPHconstraintFlag = 3; + } else if ((strcmpi(temp, "123") == 0) || (strcmpi(temp, "132") == 0) || (strcmpi(temp, "213") == 0) || + (strcmpi(temp, "231") == 0) || (strcmpi(temp, "312") == 0) || (strcmpi(temp, "321") == 0)) { + pSPARC_Input->NPHconstraintFlag = 4; + } + else { + printf("Cannot recognize NPH_SCALE_CONSTRAINTS: %s\n", temp); + exit(EXIT_FAILURE); + } + fscanf(input_fp, "%*[^\n]\n"); + } else if (strcmpi(str,"NPH_ANGLES:") == 0){ + fscanf(input_fp,"%d",&pSPARC_Input->NPH_angles); + fscanf(input_fp, "%*[^\n]\n"); + + if (pSPARC_Input->NPHscaleVecs[0] == 0 || pSPARC_Input->NPHscaleVecs[1] == 0 || pSPARC_Input->NPHscaleVecs[2] == 0 && pSPARC_Input->NPHconstraintFlag == 0){ + printf("Angle changing is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints imposed on them.\n"); + printf("To allow Angle changing, input NPH_ANGLES: 1, while simultaneously NPH_SCALE_VECS: 1 2 3 and omit/skip input of NPH_SCALE_CONSTRAINTS (so default: none will be triggered).\n"); + exit(EXIT_FAILURE); + } } else if (strcmpi(str,"NPT_NH_QMASS:") == 0) { fscanf(input_fp,"%d",&pSPARC_Input->NPT_NHnnos); for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC_Input->NPT_NHnnos; subscript_NPTNH_qmass++){ @@ -795,7 +852,10 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } else if (strcmpi(str,"NPT_NP_BMASS:") == 0) { fscanf(input_fp,"%lf",&pSPARC_Input->NPT_NP_bmass); fscanf(input_fp, "%*[^\n]\n"); - }else if (strcmpi(str,"EXTERNAL_PRESSURE:") == 0) { + } else if (strcmpi(str,"NPH_BMASS:") == 0) { + fscanf(input_fp,"%lf",&pSPARC_Input->NPH_bmass); + fscanf(input_fp, "%*[^\n]\n"); + } else if (strcmpi(str,"EXTERNAL_PRESSURE:") == 0) { fscanf(input_fp,"%lf",&pSPARC_Input->pressure_external); fscanf(input_fp, "%*[^\n]\n"); }else if (strcmpi(str,"EXTERNAL_STRESS:") == 0) { From a58443102feb2453368ddc46fa87a67ad9a2ab4c Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 24 Mar 2026 15:46:43 -0400 Subject: [PATCH 08/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/initialization.c | 125 ++++++++++++++++++++++++++++++++----------- 1 file changed, 94 insertions(+), 31 deletions(-) diff --git a/src/initialization.c b/src/initialization.c index 88c71de1..8e90409c 100644 --- a/src/initialization.c +++ b/src/initialization.c @@ -55,7 +55,7 @@ #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) -#define N_MEMBR 210 +#define N_MEMBR 217 /** @@ -830,7 +830,12 @@ void set_defaults(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { pSPARC_Input->NPTscaleVecs[1] = 1; pSPARC_Input->NPTscaleVecs[2] = 1; // default lattice vectors to be rescaled in NPT pSPARC_Input->NPTconstraintFlag = 0; // confinement on side length of cell. none: no length confinement (default) - pSPARC_Input->NPT_NPH_ANGLES = 0; // default: no change in angles during NPT_NP or NPH ensemble + pSPARC_Input->NPT_NP_ANGLES = 0; // default: no change in angles during NPT_NP ensemble + pSPARC_Input->NPHscaleVecs[0] = 1; + pSPARC_Input->NPHscaleVecs[1] = 1; + pSPARC_Input->NPHscaleVecs[2] = 1; // default lattice vectors to be rescaled in NPH + pSPARC_Input->NPHconstraintFlag = 0; // confinement on side length of cell. none: no length confinement (default) + pSPARC_Input->NPH_ANGLES = 0; // default: no change in angles during NPH ensemble pSPARC_Input->NPT_NHnnos = 0; // default amount of thermo variable for NPT_NH. If MDMeth is this but nnos is 0, program will stop for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < L_QMASS; subscript_NPTNH_qmass++){ pSPARC_Input->NPT_NHqmass[subscript_NPTNH_qmass] = 0.0; @@ -844,6 +849,7 @@ void set_defaults(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } pSPARC_Input->NPT_NP_qmass = 0.0; // default mass of thermo variables for NPT_NP. If MDMeth is this but qmass is 0, program will stop pSPARC_Input->NPT_NP_bmass = 0.0; // default mass of thermo variables for NPT_NP. If MDMeth is this but bmass is 0, program will stop + pSPARC_Input->NPH_bmass = 0.0; // default mass of thermo variables for NPH. If MDMeth is this but bmass is 0, program will stop /* Default Relax parameters */ pSPARC_Input->NLCG_sigma = 0.5; @@ -1458,6 +1464,12 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { pSPARC->NPTscaleVecs[1] = pSPARC_Input->NPTscaleVecs[1]; pSPARC->NPTscaleVecs[2] = pSPARC_Input->NPTscaleVecs[2]; pSPARC->NPTconstraintFlag = pSPARC_Input->NPTconstraintFlag; + pSPARC->NPT_NP_ANGLES = pSPARC_Input->NPT_NP_ANGLES; + pSPARC->NPHscaleVecs[0] = pSPARC_Input->NPHscaleVecs[0]; + pSPARC->NPHscaleVecs[1] = pSPARC_Input->NPHscaleVecs[1]; + pSPARC->NPHscaleVecs[2] = pSPARC_Input->NPHscaleVecs[2]; + pSPARC->NPHconstraintFlag = pSPARC_Input->NPHconstraintFlag; + pSPARC->NPH_ANGLES = pSPARC_Input->NPH_ANGLES; pSPARC->NPT_NHnnos = pSPARC_Input->NPT_NHnnos; pSPARC->ion_elec_eqT = pSPARC_Input->ion_elec_eqT; pSPARC->ion_vel_dstr = pSPARC_Input->ion_vel_dstr; @@ -1554,13 +1566,13 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { } pSPARC->NPT_NHbmass = pSPARC_Input->NPT_NHbmass; pSPARC->prtarget = pSPARC_Input->prtarget; - pSPARC->pr_external = pSPARC_Input->pr_external; + pSPARC->pressure_external = pSPARC_Input->pressure_external; for (i = 0; i < 6; i++){ pSPARC->stress_external[i] = pSPARC_Input->stress_external[i]; } - pSPARC->pr_external = pSPARC_Input->pr_external; pSPARC->NPT_NP_bmass = pSPARC_Input->NPT_NP_bmass; pSPARC->NPT_NP_qmass = pSPARC_Input->NPT_NP_qmass; + pSPARC->NPH_bmass = pSPARC->NPH_bmass; pSPARC->NLCG_sigma = pSPARC_Input->NLCG_sigma; pSPARC->L_finit_stp = pSPARC_Input->L_finit_stp; pSPARC->L_maxmov = pSPARC_Input->L_maxmov; @@ -2939,29 +2951,14 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { // check MDMeth availability if ((strcmpi(pSPARC->MDMeth,"NVT_NH") && strcmpi(pSPARC->MDMeth,"NVE") - && strcmpi(pSPARC->MDMeth,"NVK_G") && strcmpi(pSPARC->MDMeth,"NPT_NH") && strcmpi(pSPARC->MDMeth,"NPT_NP")) != 0) { + && strcmpi(pSPARC->MDMeth,"NVK_G") && strcmpi(pSPARC->MDMeth,"NPT_NH") && strcmpi(pSPARC->MDMeth,"NPT_NP") && strcmpi(pSPARC->MDMeth,"NPH")) != 0) { if (!rank){ printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - printf("MDMeth (MD Method) must be one of the following:\n\tNVT_NH\t NVE\t NVK_G\t NPT_NH\t NPT_NP\n"); + printf("MDMeth (MD Method) must be one of the following:\n\tNVT_NH\t NVE\t NVK_G\t NPT_NH\t NPT_NP\t NPH\n"); } exit(EXIT_FAILURE); } if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { // check conflict for non-orthogonal cell systems - if (! (pSPARC->NPTscaleVecs[0] * pSPARC->NPTscaleVecs[1] * pSPARC->NPTscaleVecs[2])) { - if (!rank) { - printf("\nCurrently NPT_NP only support isotropic expansion for non-orthogonal cells. Please set NPT_SCALE_VECS: 1 2 3 \n"); - printf("then set NPT_SCALE_CONSTRAINTS: 123 \n"); - } - exit(EXIT_FAILURE); - } - if (pSPARC->NPTconstraintFlag != 4) { - if (!rank) { - printf("\nCurrently NPT_NP only support isotropic expansion for non-orthogonal cells. Please add or change NPT_SCALE_CONSTRAINTS: 123"); - } - exit(EXIT_FAILURE); - } - } if (pSPARC->NPTconstraintFlag == 1) { // check conflict between NPT_SCALE_CONFINEMENTS and NPT_SCALE_VECS if (! (pSPARC->NPTscaleVecs[0] * pSPARC->NPTscaleVecs[1])) { // a or b cannot be rescaled if (!rank) { @@ -2995,6 +2992,40 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { } } } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0) { + if (pSPARC->NPHconstraintFlag == 1) { // check conflict between NPH_SCALE_CONFINEMENTS and NPH_SCALE_VECS + if (! (pSPARC->NPHscaleVecs[0] * pSPARC->NPHscaleVecs[1])) { // a or b cannot be rescaled + if (!rank) { + printf("\nNPH_SCALE_CONSTRAINTS 12 has conflict with NPH_SCALE_VECS!\n"); + } + exit(EXIT_FAILURE); + } + } + if (pSPARC->NPHconstraintFlag == 2) { + if (! (pSPARC->NPHscaleVecs[0] * pSPARC->NPHscaleVecs[2])) { // a or c cannot be rescaled + if (!rank) { + printf("\nNPH_SCALE_CONSTRAINTS 13 has conflict with NPH_SCALE_VECS!\n"); + } + exit(EXIT_FAILURE); + } + } + if (pSPARC->NPHconstraintFlag == 3) { + if (! (pSPARC->NPHscaleVecs[1] * pSPARC->NPHscaleVecs[2])) { // b or c cannot be rescaled + if (!rank) { + printf("\nNPH_SCALE_CONSTRAINTS 23 has conflict with NPH_SCALE_VECS!\n"); + } + exit(EXIT_FAILURE); + } + } + if (pSPARC->NPHconstraintFlag == 4) { + if (! (pSPARC->NPHscaleVecs[0] * pSPARC->NPHscaleVecs[1] * pSPARC->NPHscaleVecs[2])) { // a or b or c cannot be rescaled + if (!rank) { + printf("\nNPH_SCALE_CONSTRAINTS 123 has conflict with NPH_SCALE_VECS!\n"); + } + exit(EXIT_FAILURE); + } + } + } if (pSPARC->REFERENCE_CUTOFF_FAC > 0) { pSPARC->REFERENCE_CUTOFF = max(max(pSPARC->delta_x, pSPARC->delta_y), pSPARC->delta_z) * pSPARC->REFERENCE_CUTOFF_FAC; @@ -3921,11 +3952,34 @@ void write_output_init(SPARC_OBJ *pSPARC) { else if (pSPARC->NPTconstraintFlag == 2) fprintf(output_fp," 13\n"); else if (pSPARC->NPTconstraintFlag == 3) fprintf(output_fp," 23\n"); else if (pSPARC->NPTconstraintFlag == 4) fprintf(output_fp," 123\n"); + fprintf(output_fp,"NPT_NP_ANGLES: %d\n",pSPARC->NPT_NP_ANGLES); fprintf(output_fp,"NPT_NP_QMASS: %.15g\n",pSPARC->NPT_NP_qmass); fprintf(output_fp,"NPT_NP_BMASS: %.15g\n",pSPARC->NPT_NP_bmass); - fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->pr_external+pSPARC->stress_external[0] - ,pSPARC->pr_external+pSPARC->stress_external[1] - ,pSPARC->pr_external+pSPARC->stress_external[2] + fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->pressure_external+pSPARC->stress_external[0] + ,pSPARC->pressure_external+pSPARC->stress_external[1] + ,pSPARC->pressure_external+pSPARC->stress_external[2] + ,pSPARC->stress_external[3] + ,pSPARC->stress_external[4] + ,pSPARC->stress_external[5]); + + } + if(strcmpi(pSPARC->MDMeth,"NPH") == 0) { + fprintf(output_fp,"NPH_SCALE_VECS:"); + if (pSPARC->NPHscaleVecs[0] == 1) fprintf(output_fp," 1"); + if (pSPARC->NPHscaleVecs[1] == 1) fprintf(output_fp," 2"); + if (pSPARC->NPHscaleVecs[2] == 1) fprintf(output_fp," 3"); + fprintf(output_fp,"\n"); + fprintf(output_fp,"NPH_SCALE_CONSTRAINTS:"); + if (pSPARC->NPHconstraintFlag == 0) fprintf(output_fp," none\n"); + else if (pSPARC->NPHconstraintFlag == 1) fprintf(output_fp," 12\n"); + else if (pSPARC->NPHconstraintFlag == 2) fprintf(output_fp," 13\n"); + else if (pSPARC->NPHconstraintFlag == 3) fprintf(output_fp," 23\n"); + else if (pSPARC->NPHconstraintFlag == 4) fprintf(output_fp," 123\n"); + fprintf(output_fp,"NPH_ANGLES: %d\n",pSPARC->NPH_ANGLES); + fprintf(output_fp,"NPH_BMASS: %.15g\n",pSPARC->NPH_bmass); + fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->pressure_external+pSPARC->stress_external[0] + ,pSPARC->pressure_external+pSPARC->stress_external[1] + ,pSPARC->pressure_external+pSPARC->stress_external[2] ,pSPARC->stress_external[3] ,pSPARC->stress_external[4] ,pSPARC->stress_external[5]); @@ -4334,7 +4388,7 @@ void print_orthogonal_warning(SPARC_OBJ *pSPARC, FILE *output_fp) void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { SPARC_INPUT_OBJ sparc_input_tmp; - MPI_Datatype SPARC_types[N_MEMBR] = {MPI_INT, MPI_INT, MPI_INT, /* int array */ + MPI_Datatype SPARC_types[N_MEMBR] = {MPI_INT, MPI_INT, MPI_INT, MPI_INT, /* int array */ MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, @@ -4358,7 +4412,8 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, - MPI_INT, MPI_INT, MPI_INT, MPI_INT, /* int */ + MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, + MPI_INT, MPI_INT, /* int */ MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, /* double array */ @@ -4376,10 +4431,10 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, - MPI_DOUBLE, MPI_DOUBLE, /* double */ + MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE,/* double */ MPI_CHAR, MPI_CHAR, MPI_CHAR, MPI_CHAR, MPI_CHAR, /* char */ MPI_CHAR, MPI_CHAR, MPI_CHAR, MPI_CHAR, MPI_CHAR}; - int blens[N_MEMBR] = {3, 3, 7, /* int array */ + int blens[N_MEMBR] = {3, 3, 3, 7, /* int array */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -4403,7 +4458,8 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, /* int */ + 1, 1, 1, 1, 1, + 1, 1,/* int */ 9, 3, L_QMASS, L_kpoint, L_kpoint, L_kpoint, 6, 6,/* double array */ 1, 1, 1, 1, 1, @@ -4419,6 +4475,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, /* double */ 32, 32, 32, L_STRING, L_STRING, /* char */ L_STRING, L_STRING, L_STRING, L_STRING, L_STRING}; @@ -4429,6 +4486,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_Get_address(&sparc_input_tmp, &base); // int array type MPI_Get_address(&sparc_input_tmp.NPTscaleVecs, addr + i++); + MPI_Get_address(&sparc_input_tmp.NPHscaleVecs, addr + i++); MPI_Get_address(&sparc_input_tmp.EXXDownsampling, addr + i++); MPI_Get_address(&sparc_input_tmp.PrintPsiFlag, addr + i++); // int type @@ -4511,6 +4569,9 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_Get_address(&sparc_input_tmp.d3Flag, addr + i++); MPI_Get_address(&sparc_input_tmp.NPT_NHnnos, addr + i++); MPI_Get_address(&sparc_input_tmp.NPTconstraintFlag, addr + i++); + MPI_Get_address(&sparc_input_tmp.NPHconstraintFlag, addr + i++); + MPI_Get_address(&sparc_input_tmp.NPT_NP_ANGLES, addr + i++); + MPI_Get_address(&sparc_input_tmp.NPH_ANGLES, addr + i++); MPI_Get_address(&sparc_input_tmp.MAXIT_FOCK, addr + i++); MPI_Get_address(&sparc_input_tmp.ExxAcc, addr + i++); MPI_Get_address(&sparc_input_tmp.ExxMemBatch, addr + i++); @@ -4559,9 +4620,10 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_Get_address(&sparc_input_tmp.kredx, addr + i++); MPI_Get_address(&sparc_input_tmp.kredy, addr + i++); MPI_Get_address(&sparc_input_tmp.kredz, addr + i++); + MPI_Get_address(&sparc_input_tmp.stress_rel_scale, addr + i++); MPI_Get_address(&sparc_input_tmp.stress_external, addr + i++); + - MPI_Get_address(&sparc_input_tmp.stress_rel_scale, addr + i++); // double type MPI_Get_address(&sparc_input_tmp.range_x, addr + i++); MPI_Get_address(&sparc_input_tmp.range_y, addr + i++); @@ -4613,6 +4675,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_Get_address(&sparc_input_tmp.prtarget, addr + i++); MPI_Get_address(&sparc_input_tmp.NPT_NP_qmass, addr + i++); MPI_Get_address(&sparc_input_tmp.NPT_NP_bmass, addr + i++); + MPI_Get_address(&sparc_input_tmp.NPH_bmass, addr + i++); MPI_Get_address(&sparc_input_tmp.TOL_FOCK, addr + i++); MPI_Get_address(&sparc_input_tmp.TOL_SCF_INIT, addr + i++); MPI_Get_address(&sparc_input_tmp.hyb_range_fock, addr + i++); @@ -4636,7 +4699,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_Get_address(&sparc_input_tmp.F_rel_scale, addr + i++); MPI_Get_address(&sparc_input_tmp.relaxPrTarget, addr + i++); - MPI_Get_address(&sparc_input_tmp.pr_external, addr + i++); + MPI_Get_address(&sparc_input_tmp.pressure_external, addr + i++); // char type From ed027f9f2fd3a63d5775c348336893de5a1f3eb2 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 24 Mar 2026 16:37:26 -0400 Subject: [PATCH 09/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 50 +++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index 8e2d8f0a..1fdc0ba7 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -859,16 +859,16 @@ typedef struct _SPARC_OBJ{ double amu2au; // conversion factor for atomic mass unit -> atomic unit of mass double fs2atu; // conversion factor for femto second -> atomic unit of time (Jiffy) double relaxPrTarget; // Target pressure for cell relaxation in GPa - // NPT + // NPT OR NPH common int NPTscaleVecs[3]; // which lattice vector can be rescaled? int NPTconstraintFlag; // confinement on side length of cell. none: no length confinement (default); 1: a:b keeps unchanged; 2: a:c keeps unchanged; // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. int NPTisotropicFlag; // whether it is an isotropic cell expansion; a:b:c keeps similar during NPT. // For NPT_NH, if all 3 lattive vectors are scalable, it will be an isotropic expansion; // For NPT_NP, if all 3 lattive vectors are scalable, AND NPTconstraintFlag is 4, it will be an isotropic expansion. - double prtarget; // Target pressure of barostatic system, used in both NPT_NH and NPT_NP - double scale; // length ratio of the size of cell in NPT, used in both NPT_NH and NPT_NP - double volumeCell; // volume of the cell, used in both NPT_NH and NPT_NP + double prtarget; // Target pressure of barostatic system, used in NPT_NH + double scale; // length ratio of the size of cell in NPT, used in both NPT_NH + double volumeCell; // volume of the cell, used in NPT_NH, NPT_NP, NPH double initialLatVecLength[3]; // used for outputting LATVEC_SCALE // NPT-NH int NPT_NHnnos; // amount of thermostat variables in the Nose-Hoover chain, it should be smaller than 100 @@ -879,17 +879,13 @@ typedef struct _SPARC_OBJ{ double vlogv; // Velocity of virtual baro variables double xlogs[L_QMASS]; // Positions of virtual thermal variables double Hamiltonian_NPT_NH; // Hamiltonian of the NPT-NH system - // NPT-NP - int maxTimeIter; // largest allowed amount of iteration + // NPT-NP AND NPH common double pr_external; // Externally applied hydrostatic pressure, used in NPT_NP and NPH double stress_external[6]; // Externally applied anisotropic stress (applied separately from pr_external), used in NPT_NP and NPH //In NPT_NP and NPH, the target_stress[i] = pr_external+stress_external[i]; in contrast to NPT_NH where there is just target_pressure. - double NPT_NP_qmass; // fictitious mass of thermostat (qmass) used in NPT_NP - double NPT_NP_bmass; // fictitious mass of barostat (bmass) used in NPT_NP - double Pm_ion[9]; + int maxTimeIter; // largest allowed amount of iteration double full_lattice[9]; // Lattice_vectors scaled by LATVEC scale double reciprocal_lattice[9]; //Reciprocal (inverse matrix) lattice of the full cell (i.e of lattice_vector*LATVEC_SCALE), - //Note that reciprocal lattice is stored as ColumnMajor (since original lattice is rowMajor), and it lacks a factor of 2\pi double metric_tensor[9]; // G tensor, for barostat control double reciprocal_metric_tensor[9]; // G tensor associated with reciprocal lattice vectors, for barostat control double initialLatVecAngles[3]; // for keeping lattice vector angles fixed in case of NPT_NP or NPH with constraints @@ -899,7 +895,6 @@ typedef struct _SPARC_OBJ{ double external_stress_lattice[9]; //external_stress matrix multiply reciprocal_metric_tensor double external_stress_cartesian[9]; //external_stress matrix multiply reciprocal_metric_tensor double constraint_stress[9]; // Stress generated by constraining the evolution of cell lattice vectors lengths or angles - double Kbaro; // kinetic energy of barostat variables double Ubaro; // potential energy of barostat variables double SNOSE[3]; // Thermostat control related information: Position variable of thermostat, velocity of thermostat, position variable at previous time step @@ -907,11 +902,19 @@ typedef struct _SPARC_OBJ{ double Uther; // potential energy of thermostat variable double Hamiltonian_NPT_NP; // Hamiltonian of the NPT-NP system double init_Hamil_NPT_NP; // initial Hamiltonian of the system + + //NPT_NP_specific + double NPT_NP_qmass; // fictitious mass of thermostat (qmass) used in NPT_NP + double NPT_NP_bmass; // fictitious mass of barostat (bmass) used in NPT_NP + + //NPH specific + double NPH_bmass; // fictitious mass of barostat (bmass) used in NPT_NP + // Relaxation double Relax_fac; // Relaxation factor int elecgs_Count; // To count the number of times electronic ground state is calculated double *d; // Search direction in case of NLCG - double NLCG_sigma; // parameter used in NLCG + double NLCG_sigma; // parameter used in NLCG int L_history; // maximum number of relaxation steps in LBFGS stored double L_finit_stp; // finite step for line optiization double L_maxmov; // maximum allowed step size for translation @@ -1429,20 +1432,29 @@ typedef struct _SPARC_INPUT_OBJ{ double qmass; // mass parameter of Nose Hoover thermostat int NPT_NHnnos; // number of thermostat variables in NPT_NH - int NPTscaleVecs[3]; // which lattice vector can be rescaled? - int NPTconstraintFlag; // confinement on side length of cell. none: no length confinement (default); 1: a:b keeps unchanged; 2: a:c keeps unchanged; - // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. double NPT_NHqmass[L_QMASS];// qmass used in NPT_NH double NPT_NHbmass; // Bmass used in NPT_NH double prtarget; // Target pressure of NPT_NH system, UNIT on input file is GPa - double pr_external; // Externally applied hydrostatic pressure of NPT_NP or NPH system, UNIT on input file is GPa - double stress_external[6]; // Externally applied anisotropic stress tensor (applied separately from pr_external) of NPT_NP or NPH system, UNIT on input file is GPa + + int NPTscaleVecs[3]; // which lattice vector can be rescaled in NPT_NP? + int NPTconstraintFlag; // confinement on side length of cell. none: no length confinement (default); 1: a:b keeps unchanged; 2: a:c keeps unchanged; + // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. + int NPT_NP_ANGLES; // whether to allow for changing angles in NPT_NP, it can only be allowed (by setting to 1), when all lattice vectors can be rescaled using NPTscaleVecs: 1 2 3; + // and when there are NO constraints in length confinement (so no input in NPTconstraintFlag) + int NPHscaleVecs[3]; // which lattice vector can be rescaled in NPH? + int NPHconstraintFlag; // confinement on side length of cell. none: no length confinement (default); 1: a:b keeps unchanged; 2: a:c keeps unchanged; + // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPH. + int NPH_ANGLES; // whether to allow for changing angles in NPH, it can only be allowed (by setting to 1), when all lattice vectors can be rescaled using NPHscaleVecs: 1 2 3; + // and when there are NO constraints in length confinement (so no input in NPHconstraintFlag) + + double pressure_external; // Externally applied hydrostatic pressure of NPT_NP or NPH system, UNIT on input file is GPa + double stress_external[6]; // Externally applied anisotropic stress tensor (applied separately from pressure_external) for NPT_NP or NPH system, UNIT on input file is GPa //In NPT_NP and NPH, the target_stress[i] = pr_external+stress_external[i]; in contrast to NPT_NH where there is just target_pressure. double NPT_NP_qmass; // qmass used in NPT_NP - double NPT_NP_bmass; // Bmass used in NPT_NP - + double NPT_NP_bmass; // Bmass used in NPT_NP + double NPH_bmass; // Bmass used in NPH /* Walltime */ double TWtime; From a3b908b3b34f6d8da3e20cd445c8844100de3e0b Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 24 Mar 2026 18:21:23 -0400 Subject: [PATCH 10/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 5 ++- src/md.c | 88 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 72 insertions(+), 21 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index 1fdc0ba7..9a7336aa 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -888,7 +888,10 @@ typedef struct _SPARC_OBJ{ double reciprocal_lattice[9]; //Reciprocal (inverse matrix) lattice of the full cell (i.e of lattice_vector*LATVEC_SCALE), double metric_tensor[9]; // G tensor, for barostat control double reciprocal_metric_tensor[9]; // G tensor associated with reciprocal lattice vectors, for barostat control - double initialLatVecAngles[3]; // for keeping lattice vector angles fixed in case of NPT_NP or NPH with constraints + double initialLatVecAngles[3]; // for keeping lattice vector angles fixed in case of NPT_NP or NPH with constraints. + double angle_12; // Angle between lattice vectors 1 and 2. + double angle_13; // Angle between lattice vectors 1 and 3. + double angle_23; // Angle between lattice vectors 2 and 3. double rotation_matrix[9]; //For rotating between actual cell, and rotated_cell double lattice_avg_velo[9]; // Average velocity of lattice vectors double Pm_metric_tensor[9]; // Momenta of the metric_tensor diff --git a/src/md.c b/src/md.c index 6c49472e..92f561c8 100644 --- a/src/md.c +++ b/src/md.c @@ -308,10 +308,10 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); pSPARC->maxTimeIter = 30; if(pSPARC->NPT_NP_bmass == 0.0) { @@ -320,11 +320,12 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { exit(EXIT_FAILURE); } } + + fetch_MD_cell_ingredients(pSPARC, false); - - pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i1 = 0; i1 < 6; i1++){ - pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 } pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; @@ -338,15 +339,15 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable. Using a zero mass would resemble NPH ensemble, if this is the case then please choose MD_METHOD as NPH \n"); + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); exit(EXIT_FAILURE); } } if(strcmpi(pSPARC->MdMeth,"NPH")){ - pSPARC->NPT_NP_qmass = 0; + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble. If choosing MD_method as NPH with nonzero thermostat mass, it would be automatically set to zero at this point\n"); + printf("Mass of thermostat variable is zero in NPH ensemble\n"); } } @@ -357,7 +358,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->thermos_Ti = pSPARC->ion_T; pSPARC->thermos_T = pSPARC->thermos_Ti; - fetch_MD_cell_ingredients(pSPARC, false); + //Calculate initial hamitonian NPT_NP_and_NPH_init_hamiltonian(pSPARC); @@ -1451,6 +1452,11 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = pSPARC->initialLatVecAngles[2]; + pSPARC->angle_13 = pSPARC->initialLatVecAngles[1]; + pSPARC->angle_23 = pSPARC->initialLatVecAngles[0]; + } // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) @@ -1478,6 +1484,7 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ //Update LatUVec, Jacbdet, metricT, gradT, lapcT Cart2nonCart_transformMat(pSPARC); + //Update cell volume pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) @@ -1485,7 +1492,25 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_gamma_new) * 180 / M_PI; + + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } } //Update reciprocal lattice vectors, reciprocal metric tensor @@ -2490,15 +2515,27 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ if (pSPARC->Flag_latvec_scale == 0) fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); else fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); - else + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + frintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); } if(pSPARC->Calc_stress == 1){ fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); @@ -2540,6 +2577,9 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); //Using Hamiltonian of NPT_NP is NOT a bug; + // NPH is using same functions as NPT_NP with only difference of setting NPT_NP_qmass = 0 (so thermostat mass to 0). // Print atomic position if(pSPARC->PrintAtomPosFlag){ @@ -2567,10 +2607,18 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // Print length of lattice vectors if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + if (pSPARC->Flag_latvec_scale == 0){ fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else + fprintf(output_md,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } } // Print stress @@ -2643,7 +2691,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } /* - @ brief function to evaluate the qunatities of interest in a MD simulation + @ brief function to evaluate the quantities of interest in a MD simulation */ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { // Compute MD energies (TE=KE+PE)/atom and temperature From 3cb7d79df321f492617013d89fed1c533b1b0d68 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 25 Mar 2026 16:08:39 -0400 Subject: [PATCH 11/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 6 +++++- src/initialization.c | 2 +- .../standard/Al18Si18_NPTNP.inpt | 2 +- .../Al18Si18_NPTNP/standard/esparallel.sbatch | 18 ++++++++++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 tests/Al18Si18_NPTNP/standard/esparallel.sbatch diff --git a/src/include/isddft.h b/src/include/isddft.h index 9a7336aa..53e33c30 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -863,6 +863,10 @@ typedef struct _SPARC_OBJ{ int NPTscaleVecs[3]; // which lattice vector can be rescaled? int NPTconstraintFlag; // confinement on side length of cell. none: no length confinement (default); 1: a:b keeps unchanged; 2: a:c keeps unchanged; // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. + int NPT_NP_ANGLES; + int NPHscaleVecs[3]; + int NPHconstraintFlag; + int NPH_angles; int NPTisotropicFlag; // whether it is an isotropic cell expansion; a:b:c keeps similar during NPT. // For NPT_NH, if all 3 lattive vectors are scalable, it will be an isotropic expansion; // For NPT_NP, if all 3 lattive vectors are scalable, AND NPTconstraintFlag is 4, it will be an isotropic expansion. @@ -880,7 +884,7 @@ typedef struct _SPARC_OBJ{ double xlogs[L_QMASS]; // Positions of virtual thermal variables double Hamiltonian_NPT_NH; // Hamiltonian of the NPT-NH system // NPT-NP AND NPH common - double pr_external; // Externally applied hydrostatic pressure, used in NPT_NP and NPH + double pressure_external; // Externally applied hydrostatic pressure, used in NPT_NP and NPH double stress_external[6]; // Externally applied anisotropic stress (applied separately from pr_external), used in NPT_NP and NPH //In NPT_NP and NPH, the target_stress[i] = pr_external+stress_external[i]; in contrast to NPT_NH where there is just target_pressure. int maxTimeIter; // largest allowed amount of iteration diff --git a/src/initialization.c b/src/initialization.c index 8e90409c..245c1ece 100644 --- a/src/initialization.c +++ b/src/initialization.c @@ -842,7 +842,7 @@ void set_defaults(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } // default mass of thermo variables for NPT_NH. If MDMeth is this but one of qmass is 0, program will stop pSPARC_Input->NPT_NHbmass = 0.0; // default mass of baro variable for NPT_NH. If MDMeth is this but bmass is 0, program will stop pSPARC_Input->prtarget = 0.0; // default target pressure for NPT_NH. - pSPARC_Input->pr_external = 0.0; // default externally applied hydrostatic pressure for NPT_NP and NPH. + pSPARC_Input->pressure_external = 0.0; // default externally applied hydrostatic pressure for NPT_NP and NPH. for (int i = 0; i<6; ++i){ pSPARC_Input->stress_external[i] = 0.0; // default externally applied anisotropic stress for NPT_NP and NPH. diff --git a/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.inpt b/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.inpt index dcba84cd..869a8550 100644 --- a/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.inpt +++ b/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.inpt @@ -35,4 +35,4 @@ RESTART_FLAG: 0 # 1 = restart MD from .restart file if present, 0 TARGET_PRESSURE: 12 GPa NPT_NP_QMASS: 500.0 NPT_NP_BMASS: 0.05 -NPT_SCALE_CONSTRAINTS: 123 +#NPT_SCALE_CONSTRAINTS: 123 diff --git a/tests/Al18Si18_NPTNP/standard/esparallel.sbatch b/tests/Al18Si18_NPTNP/standard/esparallel.sbatch new file mode 100644 index 00000000..d4b717c6 --- /dev/null +++ b/tests/Al18Si18_NPTNP/standard/esparallel.sbatch @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -J SPARC_testsuite +#SBATCH -A gts-phanish6 +#SBATCH -qembers +#SBATCH --ntasks=8 +#SBATCH --mem-per-cpu=16G +#SBATCH -o ./Reports/Report-%j.out +#SBATCH -t2:00:00 +cd $SLURM_SUBMIT_DIR + + +module load intel-oneapi-compilers +module load intel-oneapi-mkl +module load intel-oneapi-mpi + +echo $PWD +mpirun ../../../lib/sparc -name Al18Si18_NPTNP -log_summary > Al18Si18_NPTNP.log + From fa2e875916a3879e882d5ccfb82cdcc7fc45ad30 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 25 Mar 2026 16:15:46 -0400 Subject: [PATCH 12/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index 53e33c30..bb26496e 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -864,9 +864,9 @@ typedef struct _SPARC_OBJ{ int NPTconstraintFlag; // confinement on side length of cell. none: no length confinement (default); 1: a:b keeps unchanged; 2: a:c keeps unchanged; // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. int NPT_NP_ANGLES; - int NPHscaleVecs[3]; - int NPHconstraintFlag; - int NPH_angles; + int NPHscaleVecs[3]; // Same as NPTconstraintFlag, but meant for NPH + int NPHconstraintFlag; // Same as NPTconstraintFlag, but meant for NPH + int NPH_ANGLES; // Same as NPTconstraintFlag, but meant for NPH int NPTisotropicFlag; // whether it is an isotropic cell expansion; a:b:c keeps similar during NPT. // For NPT_NH, if all 3 lattive vectors are scalable, it will be an isotropic expansion; // For NPT_NP, if all 3 lattive vectors are scalable, AND NPTconstraintFlag is 4, it will be an isotropic expansion. From e7b2cb684f22417a933308d3a13ffac5ba07e315 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 25 Mar 2026 16:17:42 -0400 Subject: [PATCH 13/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 2 +- src/readfiles.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index bb26496e..ca126573 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -863,7 +863,7 @@ typedef struct _SPARC_OBJ{ int NPTscaleVecs[3]; // which lattice vector can be rescaled? int NPTconstraintFlag; // confinement on side length of cell. none: no length confinement (default); 1: a:b keeps unchanged; 2: a:c keeps unchanged; // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. - int NPT_NP_ANGLES; + int NPT_NP_ANGLES; // Flag to decide whether changing of angles during NPT_NP ensemble is allowed int NPHscaleVecs[3]; // Same as NPTconstraintFlag, but meant for NPH int NPHconstraintFlag; // Same as NPTconstraintFlag, but meant for NPH int NPH_ANGLES; // Same as NPTconstraintFlag, but meant for NPH diff --git a/src/readfiles.c b/src/readfiles.c index ea217489..f2d92a15 100644 --- a/src/readfiles.c +++ b/src/readfiles.c @@ -778,7 +778,7 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } fscanf(input_fp, "%*[^\n]\n"); } else if (strcmpi(str,"NPT_NP_ANGLES:") == 0){ - fscanf(input_fp,"%d",&pSPARC_Input->NPT_NP_angles); + fscanf(input_fp,"%d",&pSPARC_Input->NPT_NP_ANGLES); fscanf(input_fp, "%*[^\n]\n"); if (pSPARC_Input->NPTscaleVecs[0] == 0 || pSPARC_Input->NPTscaleVecs[1] == 0 || pSPARC_Input->NPTscaleVecs[2] == 0 && pSPARC_Input->NPTconstraintFlag == 0){ @@ -826,7 +826,7 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } fscanf(input_fp, "%*[^\n]\n"); } else if (strcmpi(str,"NPH_ANGLES:") == 0){ - fscanf(input_fp,"%d",&pSPARC_Input->NPH_angles); + fscanf(input_fp,"%d",&pSPARC_Input->NPH_ANGLES); fscanf(input_fp, "%*[^\n]\n"); if (pSPARC_Input->NPHscaleVecs[0] == 0 || pSPARC_Input->NPHscaleVecs[1] == 0 || pSPARC_Input->NPHscaleVecs[2] == 0 && pSPARC_Input->NPHconstraintFlag == 0){ From bf247cb6d1353068109688fef341aad3c6247f14 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 25 Mar 2026 18:30:48 -0400 Subject: [PATCH 14/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 1 + src/include/md.h | 30 +++--- src/md.c | 234 +++++++++++++++++++++++++++++++------------ 3 files changed, 184 insertions(+), 81 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index ca126573..f0a075b3 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -902,6 +902,7 @@ typedef struct _SPARC_OBJ{ double external_stress_lattice[9]; //external_stress matrix multiply reciprocal_metric_tensor double external_stress_cartesian[9]; //external_stress matrix multiply reciprocal_metric_tensor double constraint_stress[9]; // Stress generated by constraining the evolution of cell lattice vectors lengths or angles + double kinetic_stress[9]; double Kbaro; // kinetic energy of barostat variables double Ubaro; // potential energy of barostat variables double SNOSE[3]; // Thermostat control related information: Position variable of thermostat, velocity of thermostat, position variable at previous time step diff --git a/src/include/md.h b/src/include/md.h index 0c0f5aea..7e660cbb 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -157,31 +157,27 @@ void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC); */ void NPT_NP(SPARC_OBJ *pSPARC); +void NPH(SPARC_OBJ *pSPARC); + +void NPT_NPH_main(SPARC_OBJ *pSPARC); /* @ brief: Calculates cell angles, reciprocal lattice vectors, metric and reciprocal metric tensors, for use in NPT_NP and NPH dynamics */ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC); +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell); -/* -@ brief: calculate Hamiltonian of the NPT_NP system. -*/ -void initialize_Hamiltonian(SPARC_OBJ *pSPARC); +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC); -/* -@ brief: updating momentums of thermostat and barostat variables and particles in the first half step in NPT_NP. -*/ -void updateMomentum_FirstHalf(SPARC_OBJ *pSPARC); +void transpose_and_add(double *matrix1); -/* -@ brief: updating momentums of thermostat and barostat variables and particles in the second half step in NPT_NP. -*/ -void updateMomentum_SecondHalf(SPARC_OBJ *pSPARC); +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC); -/* -@ brief: updating value of thermostat variable and length of cell and positions of particles in NPT_NP. -*/ -void updatePosition(SPARC_OBJ *pSPARC); +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional); + +void compute_constraint_stress(SPARC_OBJ *pSPARC); + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new) +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional); /** * @ brief: function to convert non cartesian to cartesian coordinates and velocities, from initialization.c */ diff --git a/src/md.c b/src/md.c index 92f561c8..163c9c0e 100644 --- a/src/md.c +++ b/src/md.c @@ -12,7 +12,7 @@ #include #include #include - +#include #ifdef USE_MKL #include #else @@ -375,7 +375,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { // pSPARC->thermos_Ti = pSPARC->elec_T; pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i1 = 0; i1 < 6; i1++){ pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 }// transfer from GPa to Ha/Bohr^3 @@ -1433,6 +1433,15 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ double old_cell[9]; double new_cell[9]; + double NPT_NPH_bmass; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + NPT_NPH_bmass = pSPARC->NPT_NP_bmass; + } + else { + NPT_NPH_bmass = pSPARC->NPH_bmass; + } + + if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; @@ -1558,7 +1567,12 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; } - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); @@ -1643,13 +1657,14 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, dou cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); + double total_internal_stress[9]; for (int i = 0; i < 9; i++){ - pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i]) + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i]) } - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); } @@ -1659,7 +1674,12 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants - double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + double baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; double baro_const3 = 1.0 / baro_const1; double ktemp; @@ -1694,7 +1714,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b,1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper @@ -1708,7 +1728,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ -update momentum */ -void NPT_NPH_main(SPARC_OBJ *pSPARC){ +void NPT_NPH_main(SPARC_OBJ *pSPARC) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); double ktemp; @@ -1719,19 +1739,36 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ double internal_stress_cartesian[9]; double internal_stress_fractional[9]; //Initialize some useful constants - double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + double baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; double baro_const3 = 1.0 / baro_const1; // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - double sumAllHamilTerms = pSPARC->Etot;//Potential; Term 2 in Eqn.10 in Hernandez paper + double sumAllHamilTerms = pSPARC->Etot; //Potential; Term 2 in Eqn.10 in Hernandez paper sumAllHamilTerms += pSPARC->KE + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + } + else { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + } + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + #ifdef DEBUG if (rank == 0) { printf("\n"); @@ -1744,7 +1781,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } } #endif // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// @@ -1804,18 +1846,25 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ // Eqn. 18h Hernandez paper for (int i = 0; i < 9; i++){ temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } - if (pSPARC->NPT_NP_NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } } //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress for (int i = 0; i < 9; i++){ temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } @@ -1840,7 +1889,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ //Update the kinetic energy of the barostat pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) @@ -1871,9 +1920,15 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - //Calculate/Update total energy (Hamiltonian) + // Calculate/Update the Hamiltonian (constant of motion) sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); // Calculate the Hamiltonian (constant of motion) + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } //Optionall write all individual energy contributions to the Hamiltonian to an output file @@ -1934,7 +1989,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ if (rank == 0) printf("factor is %12.9f\n", factor); #endif - if ((1.0 - factor*pSPARC->MD_dt/pSPARC->NPT_NP_qmass) < 0.0){ + if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ if (rank == 0) printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); exit(EXIT_FAILURE); @@ -1962,11 +2017,9 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ TimeIter++; //it iteration count exceeds max iteration counts, exit if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",S_new[row * 3 + 0], - S_new[row *3 + 1], S_new[row * 3 + 2]); - printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); + printf("%15.7f \n", S_new); + printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); } } #ifdef DEBUG @@ -2008,7 +2061,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC){ pSPARC->Kbaro = pSPARC->Kbaro / pSPARC->volumeCell / pSPARC->volumeCell; //Kinetic //Update the Potential energy of the barostat based on new metric tensor - pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential @@ -2072,7 +2125,13 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); @@ -2121,7 +2180,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0/baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + double thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); // Calculating constraint stress for (int i = 0; i < 9; i++){ @@ -2136,7 +2195,14 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do bool converged; // determine whether the iteration converges or not int TimeIter = 0; // current iteration count const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); double baro_const7; double det_temp_metric_tensor; @@ -2249,9 +2315,19 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl bool converged; // determine whether the iteration converges or not int TimeIter = 0; // current iteration count const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const3 = 0.5 / baro_const0; - double baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + double baro_const0, baro_const3, baro_const5; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + //Initialize empty temporary matrices and vectors double temp_mat[9]; @@ -2286,7 +2362,7 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl // Eqn. 18b Hernandez paper for (int i = 0; i < 9; i++){ temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } @@ -2578,7 +2654,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); //Using Hamiltonian of NPT_NP is NOT a bug; + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); //Using Hamiltonian of NPT_NP is NOT a bug; // NPH is using same functions as NPT_NP with only difference of setting NPT_NP_qmass = 0 (so thermostat mass to 0). // Print atomic position @@ -2618,7 +2694,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } + } } // Print stress @@ -2963,19 +3039,64 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":NPT_NP_Sv: %.15g\n", pSPARC->Sv_NPT_NP); // velocity of virtual thermal parameter - fprintf(mdout,":NPT_NP_Pm: %.15g %.15g %.15g\n", pSPARC->Pm_NPT_NP[0], pSPARC->Pm_NPT_NP[1], pSPARC->Pm_NPT_NP[2]); // velocity of virtual baro parameter - fprintf(mdout,":NPT_NP_S: %.15g\n", pSPARC->S_NPT_NP); // value of virtual thermal parameter - fprintf(mdout,":NPT_NP_range_x_velo: %.15g\n", pSPARC->range_x_velo); // velocity of virtual x baro parameter - fprintf(mdout,":NPT_NP_range_y_velo: %.15g\n", pSPARC->range_y_velo); // velocity of virtual y baro parameter - fprintf(mdout,":NPT_NP_range_z_velo: %.15g\n", pSPARC->range_z_velo); // velocity of virtual z baro parameter - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(output_md,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + // Print extended system parameters in case of NPH + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(output_md,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); } // Print temperature fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); @@ -3131,18 +3252,8 @@ void RestartMD(SPARC_OBJ *pSPARC) { if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { if (strcmpi(str,":NPT_NP_QMASS:") == 0) fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_Sv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->Sv_NPT_NP); - else if (strcmpi(str,":NPT_NP_S:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->S_NPT_NP); else if (strcmpi(str,":NPT_NP_BMASS:") == 0) fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":NPT_NP_range_x_velo:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->range_x_velo); - else if (strcmpi(str,":NPT_NP_range_y_velo:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->range_y_velo); - else if (strcmpi(str,":NPT_NP_range_z_velo:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->range_z_velo); else if (strcmpi(str,":CELL:") == 0) { double nowRange_x, nowRange_y, nowRange_z; fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); @@ -3272,13 +3383,8 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->Sv_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->S_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); @@ -3292,7 +3398,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } if(pSPARC->RestartFlag == 1) { pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)) { + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { reinitialize_mesh_NPT(pSPARC); } } From ee3d76200d0cf05f1672caad833f21284d5c74bb Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 25 Mar 2026 18:38:32 -0400 Subject: [PATCH 15/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/md.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/include/md.h b/src/include/md.h index 7e660cbb..6ff60c68 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -137,8 +137,8 @@ void VelocityParticle (SPARC_OBJ *pSPARC); */ void PositionParticleCell(SPARC_OBJ *pSPARC); -/** - * @brief Write the re-initialized parameters into the output file. +/* + @brief Write the re-initialized parameters into the output file. */ void write_output_reinit_NPT(SPARC_OBJ *pSPARC); @@ -155,6 +155,7 @@ void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC); /* @ brief: Performs Molecular Dynamics using NPT_NP. */ + void NPT_NP(SPARC_OBJ *pSPARC); void NPH(SPARC_OBJ *pSPARC); @@ -183,7 +184,7 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl */ void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord); -/** +/* * @brief: function to convert cartesian to non cartesian coordinates and velocities, from initialization.c */ void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord); From a6f02f42efce1a8778ac950010c2144c05b342ad Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 25 Mar 2026 18:42:31 -0400 Subject: [PATCH 16/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/md.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/md.h b/src/include/md.h index 6ff60c68..bd951585 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -176,7 +176,7 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, dou void compute_constraint_stress(SPARC_OBJ *pSPARC); -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new) +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new); void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional); /** From 5e7d65966b28f115e915a6de974b2b9c8610e367 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 25 Mar 2026 18:51:00 -0400 Subject: [PATCH 17/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 5 ++-- src/md.c | 56 ++++++++++++++++++++------------------------ 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index f0a075b3..fc99c645 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -909,8 +909,9 @@ typedef struct _SPARC_OBJ{ double Kther; // kinetic energy of thermostat variable double Uther; // potential energy of thermostat variable double Hamiltonian_NPT_NP; // Hamiltonian of the NPT-NP system - double init_Hamil_NPT_NP; // initial Hamiltonian of the system - + double Hamiltonian_NPH; // Hamiltonian of NPH system + double init_Hamil_NPT_NP; // initial Hamiltonian in NPT_NP ensemble + double init_Hamil_NPH; // initial Hamiltonian in NPH ensemble //NPT_NP_specific double NPT_NP_qmass; // fictitious mass of thermostat (qmass) used in NPT_NP double NPT_NP_bmass; // fictitious mass of barostat (bmass) used in NPT_NP diff --git a/src/md.c b/src/md.c index 163c9c0e..c54b9eb2 100644 --- a/src/md.c +++ b/src/md.c @@ -344,7 +344,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { } } - if(strcmpi(pSPARC->MdMeth,"NPH")){ + if(strcmpi(pSPARC->MDMeth,"NPH")){ pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH if (!rank) { printf("Mass of thermostat variable is zero in NPH ensemble\n"); @@ -389,7 +389,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - if(strcmpi(pSPARC->MdMeth,"NPH")){ + if(strcmpi(pSPARC->MDMeth,"NPH")){ pSPARC->NPT_NP_qmass = 0; } @@ -1085,7 +1085,7 @@ void PositionParticleCell(SPARC_OBJ *pSPARC) { count ++; } // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlog v * rescale); + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; @@ -1659,12 +1659,12 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, dou double total_internal_stress[9]; for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i]) + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i]); } cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); + double internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); } @@ -1672,13 +1672,14 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, dou void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - + //Initialize some useful constants + double baro_const1; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } else{ - double baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; double baro_const3 = 1.0 / baro_const1; @@ -1739,11 +1740,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { double internal_stress_cartesian[9]; double internal_stress_fractional[9]; //Initialize some useful constants + double baro_const1; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } else{ - double baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; double baro_const3 = 1.0 / baro_const1; @@ -2180,7 +2182,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0/baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - double thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); // Calculating constraint stress for (int i = 0; i < 9; i++){ @@ -2600,7 +2602,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - frintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); if (pSPARC->Flag_latvec_scale == 0){ fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); @@ -3048,19 +3050,19 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); } else { - fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); } - fprintf(output_md,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 ,pSPARC->stress_external[3] * 29421.02648438959 @@ -3078,19 +3080,19 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); } else { - fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); } - fprintf(output_md,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 ,pSPARC->stress_external[3] * 29421.02648438959 @@ -3324,13 +3326,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->Sv_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->S_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); From 2cd927ccf5ffeab5e25a305d73556e836043dff7 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 25 Mar 2026 19:19:12 -0400 Subject: [PATCH 18/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/md.h | 2 +- src/md.c | 215 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 154 insertions(+), 63 deletions(-) diff --git a/src/include/md.h b/src/include/md.h index bd951585..824cbc71 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -12,7 +12,7 @@ #define MD_H #include "isddft.h" - +#include /** * @ brief Main function of molecular dynamics */ diff --git a/src/md.c b/src/md.c index c54b9eb2..f5f80fd5 100644 --- a/src/md.c +++ b/src/md.c @@ -1870,17 +1870,32 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } - if (ISIF == 10){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPT_NP_ANGLES == 0){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPT_NP_ANGLES == 0){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } } - if (ISIF == 11){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPH_ANGLES == 0){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPH_ANGLES == 0){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); @@ -1962,17 +1977,32 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); //Now impose the constraints on it - if (ISIF == 10){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPT_NP_ANGLES == 0){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPT_NP_ANGLES == 0){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } } - if (ISIF == 11){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPH_ANGLES == 0){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPH_ANGLES == 0){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } } //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints @@ -2140,31 +2170,62 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (ISIF == 8){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (ISIF == 9){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPT_NP_ANGLES == 0){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (ISIF == 10){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; + // Only |c| varies, |a| and |b| are fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPT_NP_ANGLES == 0){ + gpig[0] = 0; + gpig[4] = 0; + } } - // Only |c| varies, |a| and |b| are fixed; and all angles between lattice vectors are FIXED - else if (ISIF == 11){ - gpig[0] = 0; - gpig[4] = 0; + else { + if (pSPARC->NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPH_ANGLES == 0){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + // Only |c| varies, |a| and |b| are fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPH_ANGLES == 0){ + gpig[0] = 0; + gpig[4] = 0; + } } constraint_velocity[0] = gpig[0] * baro_const4; @@ -2180,7 +2241,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ constraint_velocity[7] = constraint_velocity[5]; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0/baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); @@ -2266,33 +2327,63 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } } - if (ISIF >= 7){ - if (ISIF == 8){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } - else if (ISIF == 9){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } + else if (pSPARC->NPTconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + } - for (int i = 0; i < 9; i++){ + else { + if (pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + } + + + for (int i = 0; i < 9; i++){ temp_metric_tensor[i] = new_metric_tensor[i]; - } } for (int i = 0; i < 9; i++){ @@ -3286,7 +3377,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { pSPARC->range_z = nowRange_z; } else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_T i); + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); else if (strcmpi(str,":TARGET_PRESSURE:") == 0) fscanf(rst_fp,"%lf", &pSPARC->prtarget); else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) From fbd2308a67edc3f960676d6aac673d98b3fdeb0a Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 25 Mar 2026 19:59:18 -0400 Subject: [PATCH 19/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/md.c b/src/md.c index f5f80fd5..3f51a5b0 100644 --- a/src/md.c +++ b/src/md.c @@ -1430,7 +1430,9 @@ void transpose_and_add(double *matrix1){ Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix */ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double old_cell[9]; double new_cell[9]; double NPT_NPH_bmass; @@ -1503,7 +1505,7 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; //Update LATVEC_SCALE and LatVec if (pSPARC->Flag_latvec_scale == 1){ @@ -1598,6 +1600,9 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + int count = 0; pSPARC->KE = 0.0; @@ -1614,7 +1619,8 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ - + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); for (int i = 0; i < 9; i++){ @@ -2141,7 +2147,8 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { void compute_constraint_stress(SPARC_OBJ *pSPARC){ - + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants double a_norm; double b_norm; double c_norm; double da_dt_norm; double db_dt_norm; double dc_dt_norm; @@ -2161,7 +2168,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper } else{ - baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper } @@ -2254,6 +2261,8 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants bool converged; // determine whether the iteration converges or not int TimeIter = 0; // current iteration count @@ -2263,7 +2272,7 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); } else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); } double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); @@ -2403,7 +2412,8 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ - + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants bool converged; // determine whether the iteration converges or not int TimeIter = 0; // current iteration count @@ -2935,7 +2945,7 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { cc = 0; // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(sizeof(double), 9); + double *lattice = (double *)calloc(9, sizeof(double)); double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; double dr[3]; int row, col; @@ -3472,7 +3482,6 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); From 1b90c1a9ac07be6ed154001005c6342f011847cf Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Thu, 26 Mar 2026 12:28:43 -0400 Subject: [PATCH 20/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/initialization.c | 14 +++++++++++++ src/md.c | 47 ++++++++++++++++++++++---------------------- src/readfiles.c | 12 ----------- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/initialization.c b/src/initialization.c index 245c1ece..b7cb6375 100644 --- a/src/initialization.c +++ b/src/initialization.c @@ -2991,6 +2991,13 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { exit(EXIT_FAILURE); } } + if (pSPARC->NPT_NP_ANGLES==1){ + if (pSPARC_Input->NPTscaleVecs[0] == 0 || pSPARC_Input->NPTscaleVecs[1] == 0 || pSPARC_Input->NPTscaleVecs[2] == 0 || pSPARC_Input->NPTconstraintFlag != 0){ + printf("Angle changing is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints imposed on them.\n"); + printf("To allow Angle changing, input NPT_NP_ANGLES: 1, while simultaneously NPT_SCALE_VECS: 1 2 3 and omit/skip input of NPT_SCALE_CONSTRAINTS (so default: none will be triggered) or input NPT_SCALE_CONSTRAINTS: none.\n"); + exit(EXIT_FAILURE); + } + } } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0) { if (pSPARC->NPHconstraintFlag == 1) { // check conflict between NPH_SCALE_CONFINEMENTS and NPH_SCALE_VECS @@ -3025,6 +3032,13 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { exit(EXIT_FAILURE); } } + if (pSPARC->NPH_ANGLES==1){ + if (pSPARC_Input->NPHscaleVecs[0] == 0 || pSPARC_Input->NPHscaleVecs[1] == 0 || pSPARC_Input->NPHscaleVecs[2] == 0 || pSPARC_Input->NPHconstraintFlag != 0){ + printf("Angle changing is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints imposed on them.\n"); + printf("To allow Angle changing, input NPH_ANGLES: 1, while simultaneously NPH_SCALE_VECS: 1 2 3 and omit/skip input of NPH_SCALE_CONSTRAINTS (so default: none will be triggered) or input NPH_SCALE_CONSTRAINTS: none.\n"); + exit(EXIT_FAILURE); + } + } } if (pSPARC->REFERENCE_CUTOFF_FAC > 0) { diff --git a/src/md.c b/src/md.c index 3f51a5b0..6a7e6de3 100644 --- a/src/md.c +++ b/src/md.c @@ -376,8 +376,8 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { // pSPARC->thermos_Ti = pSPARC->elec_T; pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i1 = 0; i1 < 6; i1++){ - pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 }// transfer from GPa to Ha/Bohr^3 pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; @@ -1877,28 +1877,28 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; pSPARC->Pm_metric_tensor[5] = 0; pSPARC->Pm_metric_tensor[2] = 0; } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } } else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; pSPARC->Pm_metric_tensor[5] = 0; pSPARC->Pm_metric_tensor[2] = 0; } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } @@ -1984,28 +1984,28 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { //Now impose the constraints on it if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; pSPARC->Pm_metric_tensor[5] = 0; pSPARC->Pm_metric_tensor[2] = 0; } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } } else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; pSPARC->Pm_metric_tensor[5] = 0; pSPARC->Pm_metric_tensor[2] = 0; } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } @@ -2191,7 +2191,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ } // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPT_NP_ANGLES == 0){ + else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ gpig[8] = 0; gpig[7] = 0; gpig[6] = 0; @@ -2199,9 +2199,8 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ gpig[2] = 0; } - // Only |c| varies, |a| and |b| are fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPT_NP_ANGLES == 0){ - gpig[0] = 0; + else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + gpig[0] = 0; gpig[4] = 0; } } @@ -2220,7 +2219,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ } // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPH_ANGLES == 0){ + else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ gpig[8] = 0; gpig[7] = 0; gpig[6] = 0; @@ -2228,9 +2227,8 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ gpig[2] = 0; } - // Only |c| varies, |a| and |b| are fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPH_ANGLES == 0){ - gpig[0] = 0; + else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + gpig[0] = 0; gpig[4] = 0; } } @@ -2360,7 +2358,11 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do new_metric_tensor[3] = new_metric_tensor[1]; new_metric_tensor[6] = new_metric_tensor[2]; new_metric_tensor[7] = new_metric_tensor[5]; - } + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } } else { @@ -2387,12 +2389,11 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do new_metric_tensor[3] = new_metric_tensor[1]; new_metric_tensor[6] = new_metric_tensor[2]; new_metric_tensor[7] = new_metric_tensor[5]; - } - } - + } - for (int i = 0; i < 9; i++){ + for (int i = 0; i < 9; i++){ temp_metric_tensor[i] = new_metric_tensor[i]; + } } for (int i = 0; i < 9; i++){ diff --git a/src/readfiles.c b/src/readfiles.c index f2d92a15..53bb4840 100644 --- a/src/readfiles.c +++ b/src/readfiles.c @@ -780,12 +780,6 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } else if (strcmpi(str,"NPT_NP_ANGLES:") == 0){ fscanf(input_fp,"%d",&pSPARC_Input->NPT_NP_ANGLES); fscanf(input_fp, "%*[^\n]\n"); - - if (pSPARC_Input->NPTscaleVecs[0] == 0 || pSPARC_Input->NPTscaleVecs[1] == 0 || pSPARC_Input->NPTscaleVecs[2] == 0 && pSPARC_Input->NPTconstraintFlag == 0){ - printf("Angle changing is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints imposed on them.\n"); - printf("To allow Angle changing, input NPT_NP_ANGLES: 1, while simultaneously NPT_SCALE_VECS: 1 2 3 and omit/skip input of NPT_SCALE_CONSTRAINTS (so default: none will be triggered).\n"); - exit(EXIT_FAILURE); - } } else if (strcmpi(str,"NPH_SCALE_VECS:") == 0) { int dir[3] = {0, 0, 0}; pSPARC_Input->NPHscaleVecs[0] = 0; pSPARC_Input->NPHscaleVecs[1] = 0; pSPARC_Input->NPHscaleVecs[2] = 0; @@ -828,12 +822,6 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } else if (strcmpi(str,"NPH_ANGLES:") == 0){ fscanf(input_fp,"%d",&pSPARC_Input->NPH_ANGLES); fscanf(input_fp, "%*[^\n]\n"); - - if (pSPARC_Input->NPHscaleVecs[0] == 0 || pSPARC_Input->NPHscaleVecs[1] == 0 || pSPARC_Input->NPHscaleVecs[2] == 0 && pSPARC_Input->NPHconstraintFlag == 0){ - printf("Angle changing is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints imposed on them.\n"); - printf("To allow Angle changing, input NPH_ANGLES: 1, while simultaneously NPH_SCALE_VECS: 1 2 3 and omit/skip input of NPH_SCALE_CONSTRAINTS (so default: none will be triggered).\n"); - exit(EXIT_FAILURE); - } } else if (strcmpi(str,"NPT_NH_QMASS:") == 0) { fscanf(input_fp,"%d",&pSPARC_Input->NPT_NHnnos); for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC_Input->NPT_NHnnos; subscript_NPTNH_qmass++){ From fe9bea4b1ad6f171f8e2597f4be5a93e54d0ef60 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Thu, 26 Mar 2026 21:41:22 -0400 Subject: [PATCH 21/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 4 + src/main.c | 2 +- src/makefile | 4 +- src/md.c | 266 +++++++++++++++++++++++++++++-------------- 4 files changed, 187 insertions(+), 89 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index fc99c645..0d098672 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -912,10 +912,14 @@ typedef struct _SPARC_OBJ{ double Hamiltonian_NPH; // Hamiltonian of NPH system double init_Hamil_NPT_NP; // initial Hamiltonian in NPT_NP ensemble double init_Hamil_NPH; // initial Hamiltonian in NPH ensemble + //NPT_NP_specific double NPT_NP_qmass; // fictitious mass of thermostat (qmass) used in NPT_NP double NPT_NP_bmass; // fictitious mass of barostat (bmass) used in NPT_NP + double temperature; + double internal_pressure; + FILE *fp_energy; //NPH specific double NPH_bmass; // fictitious mass of barostat (bmass) used in NPT_NP diff --git a/src/main.c b/src/main.c index 0eb9a17b..52149771 100644 --- a/src/main.c +++ b/src/main.c @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) { // Read files and initialize Initialize(&SPARC, argc, argv); - if (SPARC.MDFlag == 1) + if (SPARC.MDFlag == 1) main_MD(&SPARC); else if (SPARC.RelaxFlag != 0) main_Relax(&SPARC); diff --git a/src/makefile b/src/makefile index b80ffdf9..e15c5de1 100644 --- a/src/makefile +++ b/src/makefile @@ -13,7 +13,7 @@ USE_DP_SUBEIG = 0 # Set USE_FFTW = 1 to use FFTW for fast Fourier transform in vdWDF. Don't open it together with USE_MKL USE_FFTW = 0 # Set DEBUG_MODE = 1 to run with debug mode and print debug output -DEBUG_MODE = 0 +DEBUG_MODE = 1 # Set USE_SOCKET = 0 to disable compilation with socket support USE_SOCKET = 0 @@ -159,4 +159,4 @@ clean: rm -f $(OBJSC) $(LIBBASE) rm -f socket/*.o test: ../tests/SPARC_testing_script.py - cd ../tests; python SPARC_testing_script.py \ No newline at end of file + cd ../tests; python SPARC_testing_script.py diff --git a/src/md.c b/src/md.c index 6a7e6de3..651654b1 100644 --- a/src/md.c +++ b/src/md.c @@ -136,7 +136,7 @@ void main_MD(SPARC_OBJ *pSPARC) { printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); exit(EXIT_FAILURE); } - fprintf(output_md,":MDSTEP: %d\n", Count); + fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); } if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) @@ -197,6 +197,10 @@ void main_MD(SPARC_OBJ *pSPARC) { free(avgvel); free(maxvel); free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers + } } /** @@ -312,7 +316,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; + pSPARC->maxTimeIter = 100; if(pSPARC->NPT_NP_bmass == 0.0) { if (!rank) { @@ -321,9 +325,25 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { } } + if (rank == 0) { + // "w" creates a new file; "a" appends to an existing one. + pSPARC->fp_energy = fopen("MD_energies.log", "w"); + + if (pSPARC->fp_energy == NULL) { + fprintf(stderr, "Error: Could not open energy log file!\n"); + exit(EXIT_FAILURE); + } + + // Optional: Print a header to make the file readable in Excel/Python + fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", + "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); + fflush(pSPARC->fp_energy); + } + fetch_MD_cell_ingredients(pSPARC, false); - + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 } @@ -337,6 +357,8 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ if (!rank) { printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); @@ -344,23 +366,22 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { } } - if(strcmpi(pSPARC->MDMeth,"NPH")){ + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH if (!rank) { printf("Mass of thermostat variable is zero in NPH ensemble\n"); } } - - + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - + + pSPARC->thermos_Ti = pSPARC->ion_T; pSPARC->thermos_T = pSPARC->thermos_Ti; - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); } else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart @@ -372,7 +393,8 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); pSPARC->maxTimeIter = 30; - + + fetch_MD_cell_ingredients(pSPARC, false); // pSPARC->thermos_Ti = pSPARC->elec_T; pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -393,7 +415,6 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->NPT_NP_qmass = 0; } - fetch_MD_cell_ingredients(pSPARC, false); Calculate_ionic_stress(pSPARC); } @@ -1358,6 +1379,10 @@ void NPT_NP(SPARC_OBJ *pSPARC) { MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } //NPT_NPH_main routine NPT_NPH_main(pSPARC); // Reinitialize mesh size and related variables after changing size of cell @@ -1390,6 +1415,10 @@ void NPH(SPARC_OBJ *pSPARC) { MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } //NPT_NPH_main routine NPT_NPH_main(pSPARC); // Reinitialize mesh size and related variables after changing size of cell @@ -1435,21 +1464,12 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ double old_cell[9]; double new_cell[9]; - double NPT_NPH_bmass; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - NPT_NPH_bmass = pSPARC->NPT_NP_bmass; - } - else { - NPT_NPH_bmass = pSPARC->NPH_bmass; - } - - if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; //Compute Cell lattice vectors (scaled by LATVEC scale) - int row, col; + int row; for (row = 0; row < 3; row++) { pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; @@ -1464,9 +1484,9 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - pSPARC->angle_12 = pSPARC->initialLatVecAngles[2]; - pSPARC->angle_13 = pSPARC->initialLatVecAngles[1]; - pSPARC->angle_23 = pSPARC->initialLatVecAngles[0]; + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; } @@ -1525,10 +1545,11 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i<9; i++){ + for (int i = 0; i < 9; i++){ old_cell[i] = pSPARC->full_lattice[i]; } + // Calculate the inverse of lattice-vector double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; @@ -1540,7 +1561,7 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ // First compute S^{-1} for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; } // Compute LV^{-1} = V * S^{-1} * U^T @@ -1604,7 +1625,7 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ MPI_Comm_rank(MPI_COMM_WORLD, &rank); int count = 0; - + pSPARC->KE = 0.0; int ityp, atm; for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ @@ -1614,7 +1635,10 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ } } pSPARC->KE = pSPARC->KE / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]); - double temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); + pSPARC->temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); + if (rank ==0){ + printf("temperature %.6f \n",pSPARC->temperature); + } } @@ -1665,13 +1689,15 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, dou double total_internal_stress[9]; for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i]); + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) - internal_stress_fractional[i] - pSPARC->constraint_stress[i]); } cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - double internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); - + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); + if (rank ==0){ + printf("Internal pressure %.6f \n",pSPARC->internal_pressure * 29421.02648438959); + } } @@ -1684,7 +1710,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } - else{ + else { baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; @@ -1693,8 +1719,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ //Initialize empty temporary matrices and vectors double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// // Calculating kinetic energy of ions cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); @@ -1757,47 +1782,40 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { double baro_const3 = 1.0 / baro_const1; - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - - double sumAllHamilTerms = pSPARC->Etot; //Potential; Term 2 in Eqn.10 in Hernandez paper - sumAllHamilTerms += pSPARC->KE + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + double sumAllHamilTerms; + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper } else { pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } } + #endif } - #endif - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// @@ -1818,6 +1836,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic ktemp = pSPARC->kB * pSPARC->thermos_T; pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + } @@ -1835,6 +1854,8 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { for (int i = 0; i < 9; i++){ @@ -1853,11 +1874,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { // Eqn. 18h Hernandez paper for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } - + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ if (pSPARC->NPT_NP_ANGLES == 0){ compute_constraint_stress(pSPARC); @@ -1904,6 +1926,14 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } } + if (rank == 0){ + for (int i = 0; i < 9; i++){ + printf("Pm metric_tensor[%d] is %.6f\n",i,pSPARC->Pm_metric_tensor[i]); + } + } + + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; @@ -1913,8 +1943,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { //Update the kinetic energy of the barostat pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds to Eqn. 18i in Hernandez paper cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); @@ -1953,7 +1982,56 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } //Optionall write all individual energy contributions to the Hamiltonian to an output file + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("AT THE END OF FIRST HALF\n"); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); + } + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], // snose(1) in Fortran is s + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure);; + } + } + } + #endif // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// @@ -2011,6 +2089,15 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } } + + if (rank == 0){ + for (int i = 0; i < 9; i++){ + printf("Pm metric_tensor[%d] is %.6f\n",i,pSPARC->Pm_metric_tensor[i]); + } + } + + + //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints // SPARC code was doing both these steps, reference code does not seem to do @@ -2069,7 +2156,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { pSPARC->SNOSE[0] = 1.0; pSPARC->SNOSE[1] = 0.0; } - + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// @@ -2237,9 +2324,9 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ constraint_velocity[4] = gpig[4] * baro_const4; constraint_velocity[8] = gpig[8] * baro_const4; - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) / pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[0]; + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; constraint_velocity[3] = constraint_velocity[1]; constraint_velocity[6] = constraint_velocity[2]; @@ -2758,8 +2845,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); //Using Hamiltonian of NPT_NP is NOT a bug; - // NPH is using same functions as NPT_NP with only difference of setting NPT_NP_qmass = 0 (so thermostat mass to 0). + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); // Print atomic position if(pSPARC->PrintAtomPosFlag){ @@ -2787,17 +2873,22 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // Print length of lattice vectors if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); } else { - fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); } } @@ -3069,6 +3160,7 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { exit(EXIT_FAILURE); } // Update MD Count + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); fclose(mdout); @@ -3084,6 +3176,8 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { mdout = fopen(pSPARC->restart_Filename,"w"); // Print restart Count + printf("\n"); + printf("\n"); fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); // Print atomic position int atm; From bb53468f8e857048b914ea17a7017a7aefd640de Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Sat, 28 Mar 2026 14:28:35 -0400 Subject: [PATCH 22/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 7 +- src/md.c | 211 +-- src/md_check.c | 3513 +++++++++++++++++++++++++++++++++++++++++ src/md_fortran.c | 3591 ++++++++++++++++++++++++++++++++++++++++++ src/md_working_on.c | 3591 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 10778 insertions(+), 135 deletions(-) create mode 100644 src/md_check.c create mode 100644 src/md_fortran.c create mode 100644 src/md_working_on.c diff --git a/src/include/isddft.h b/src/include/isddft.h index 0d098672..9bf68678 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -912,17 +912,16 @@ typedef struct _SPARC_OBJ{ double Hamiltonian_NPH; // Hamiltonian of NPH system double init_Hamil_NPT_NP; // initial Hamiltonian in NPT_NP ensemble double init_Hamil_NPH; // initial Hamiltonian in NPH ensemble - + double Snew; //NPT_NP_specific double NPT_NP_qmass; // fictitious mass of thermostat (qmass) used in NPT_NP double NPT_NP_bmass; // fictitious mass of barostat (bmass) used in NPT_NP + //NPH specific + double NPH_bmass; // fictitious mass of barostat (bmass) used in NPT_NP double temperature; double internal_pressure; FILE *fp_energy; - //NPH specific - double NPH_bmass; // fictitious mass of barostat (bmass) used in NPT_NP - // Relaxation double Relax_fac; // Relaxation factor int elecgs_Count; // To count the number of times electronic ground state is calculated diff --git a/src/md.c b/src/md.c index 651654b1..375d9d2d 100644 --- a/src/md.c +++ b/src/md.c @@ -327,7 +327,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { if (rank == 0) { // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies.log", "w"); + pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); if (pSPARC->fp_energy == NULL) { fprintf(stderr, "Error: Could not open energy log file!\n"); @@ -1379,10 +1379,10 @@ void NPT_NP(SPARC_OBJ *pSPARC) { MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + //NPT_NPH_main routine NPT_NPH_main(pSPARC); // Reinitialize mesh size and related variables after changing size of cell @@ -1415,10 +1415,10 @@ void NPH(SPARC_OBJ *pSPARC) { MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + //NPT_NPH_main routine NPT_NPH_main(pSPARC); // Reinitialize mesh size and related variables after changing size of cell @@ -1508,12 +1508,12 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt(pSPARC->metric_tensor[0]); - pSPARC->range_y = sqrt(pSPARC->metric_tensor[4]); - pSPARC->range_z = sqrt(pSPARC->metric_tensor[8]); + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); + //Cart2nonCart_transformMat(pSPARC); //Update cell volume pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; @@ -1591,10 +1591,10 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); } else { - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); @@ -1634,11 +1634,10 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ count ++; } } - pSPARC->KE = pSPARC->KE / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]); - pSPARC->temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); - if (rank ==0){ - printf("temperature %.6f \n",pSPARC->temperature); - } + + pSPARC->KE = pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); + pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); + } @@ -1689,15 +1688,13 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, dou double total_internal_stress[9]; for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) - internal_stress_fractional[i] - pSPARC->constraint_stress[i]); + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); } cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); - if (rank ==0){ - printf("Internal pressure %.6f \n",pSPARC->internal_pressure * 29421.02648438959); - } + } @@ -1713,7 +1710,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ else { baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const2 = baro_const1 / pSPARC->SNOSE[0]; double baro_const3 = 1.0 / baro_const1; double ktemp; @@ -1722,7 +1719,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// // Calculating kinetic energy of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper @@ -1745,11 +1742,29 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b,1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + double sumAllHamilTerms; + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// } @@ -1769,7 +1784,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { //Initialize empty temporary matrices and vectors double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - + //Initialize some useful constants double baro_const1; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ @@ -1778,44 +1793,13 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { else{ baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; double baro_const3 = 1.0 / baro_const1; - double sumAllHamilTerms; + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - } - } - #endif - } + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// @@ -1833,10 +1817,11 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } #endif // Update the kinetic energy of the thermostat - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + + /*pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic ktemp = pSPARC->kB * pSPARC->thermos_T; pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - + */ } @@ -1855,7 +1840,6 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { for (int i = 0; i < 9; i++){ @@ -1864,9 +1848,8 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3,pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); for (int i = 0; i < 9; i++){ temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; @@ -1926,27 +1909,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } } - if (rank == 0){ - for (int i = 0; i < 9; i++){ - printf("Pm metric_tensor[%d] is %.6f\n",i,pSPARC->Pm_metric_tensor[i]); - } - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds to Eqn. 18i in Hernandez paper - cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; count = 0; for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ @@ -1960,34 +1928,17 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { count ++; } } - //Update the kinetic energy of the Ionic particles Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - //Now write Intenal pressure, external pressure to a file - - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - // Calculate/Update the Hamiltonian (constant of motion) - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - //Optionall write all individual energy contributions to the Hamiltonian to an output file - #ifdef DEBUG + double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + #ifdef DEBUG if (rank == 0) { printf("\n"); printf("rank %d", rank); printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("AT THE END OF FIRST HALF\n"); printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); @@ -2032,6 +1983,10 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } #endif + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// @@ -2048,13 +2003,6 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } } - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - // Now we update/Step-up the momenta of the barostat by dt/2 // This setup corresponds to Eqn. 18b in the Hernandez paper // This needs to be solved iteratively @@ -2089,15 +2037,15 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } } + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - if (rank == 0){ - for (int i = 0; i < 9; i++){ - printf("Pm metric_tensor[%d] is %.6f\n",i,pSPARC->Pm_metric_tensor[i]); - } - } - - - + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints // SPARC code was doing both these steps, reference code does not seem to do @@ -2114,11 +2062,11 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { if (rank == 0) printf("factor is %12.9f\n", factor); #endif - if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + /*if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ if (rank == 0) printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); exit(EXIT_FAILURE); - } + }*/ pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); #ifdef DEBUG @@ -2165,8 +2113,8 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); + //pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); //Before updating cell parameters, compute atom positions in fractional coordinates @@ -2179,6 +2127,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { count++; } + pSPARC->Snew = S_temp; //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor fetch_MD_cell_ingredients(pSPARC, true); @@ -2203,12 +2152,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { //Update atomic positions and restore ionic velocities count = 0; for(int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_new ); // - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_new ); // - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_new ); // - pSPARC->ion_vel[count * 3] /= pSPARC->SNOSE[0]; - pSPARC->ion_vel[count * 3 + 1] /= pSPARC->SNOSE[0]; - pSPARC->ion_vel[count * 3 + 2] /= pSPARC->SNOSE[0]; + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // + pSPARC->ion_vel[count * 3] /= S_temp; + pSPARC->ion_vel[count * 3 + 1] /= S_temp; + pSPARC->ion_vel[count * 3 + 2] /= S_temp; count ++; } @@ -2222,7 +2171,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { // Update SNOSE[0] to S_new if (pSPARC->NPT_NP_qmass > 0){ pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_new; + pSPARC->SNOSE[0] = S_temp; } // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// @@ -2252,10 +2201,10 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper } else{ - baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper } @@ -2434,9 +2383,9 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do new_metric_tensor[4] = new_metric_tensor[0]; } - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; @@ -2552,7 +2501,7 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl // Eqn. 18b Hernandez paper for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } diff --git a/src/md_check.c b/src/md_check.c new file mode 100644 index 00000000..ff738173 --- /dev/null +++ b/src/md_check.c @@ -0,0 +1,3513 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include +#include +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + NPT_NP(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPH(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers + } +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 100; + + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + + if (rank == 0) { + // "w" creates a new file; "a" appends to an existing one. + pSPARC->fp_energy = fopen("MD_energies.log", "w"); + + if (pSPARC->fp_energy == NULL) { + fprintf(stderr, "Error: Could not open energy log file!\n"); + exit(EXIT_FAILURE); + } + + // Optional: Print a header to make the file readable in Excel/Python + fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", + "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); + fflush(pSPARC->fp_energy); + } + + fetch_MD_cell_ingredients(pSPARC, false); + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble\n"); + } + } + + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + fetch_MD_cell_ingredients(pSPARC, false); + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPH")){ + pSPARC->NPT_NP_qmass = 0; + } + + Calculate_ionic_stress(pSPARC); + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +*/ +void NPT_NP(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant +This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPH(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; + + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt(pSPARC->metric_tensor[0]); + pSPARC->range_y = sqrt(pSPARC->metric_tensor[4]); + pSPARC->range_z = sqrt(pSPARC->metric_tensor[8]); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat(pSPARC); + + //Update cell volume + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + + } + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate the velocity of cell lattice vectors + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } + + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + int count = 0; + + pSPARC->KE = 0.0; + int ityp, atm; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); + count ++; + } + } + pSPARC->KE = pSPARC->KE / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]); + pSPARC->temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); + +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + free(ion_vel_fractional); + + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); + + double total_internal_stress[9]; + for (int i = 0; i < 9; i++){ + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); + + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); + +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else { + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + double ktemp; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + // Calculating kinetic energy of ions + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + double sumAllHamilTerms; + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } + } + #endif + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp; + int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + + + + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// + + + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa = 0.0; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + ktemp = pSPARC->kB * pSPARC->thermos_T; + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; + pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + + /*pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + */ + } + + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]-pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3]-pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5]-pSPARC->stress_i[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]-pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1]-pSPARC->stress_i[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]-pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4]-pSPARC->stress_i[4]; + + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) + for (int i = 0; i < 9; i++){ + temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = (internal_stress_fractional[i]) + (temp_mat_b[i]); + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + + + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); + + //Now impose the constraints on it + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints + // SPARC code was doing both these steps, reference code does not seem to do + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + ktemp = pSPARC->kB * pSPARC->thermos_T; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + /*if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + exit(EXIT_FAILURE); + }*/ + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp - S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + printf("%15.7f \n", S_new); + printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + //pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); + + + //Before updating cell parameters, compute atom positions in fractional coordinates + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); + count++; + } + + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + + //Update the Kinetic energy of the barostat based on new cell volume + //pSPARC->Kbaro = pSPARC->Kbaro / pSPARC->volumeCell / pSPARC->volumeCell; //Kinetic + + //Update the Potential energy of the barostat based on new metric tensor + //pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); + count++; + } + free(atom_pos_fractional); + + //Update atomic positions and restore ionic velocities + count = 0; + for(int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_new ); // + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_new ); // + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_new ); // + pSPARC->ion_vel[count * 3] /= S_new; + pSPARC->ion_vel[count * 3 + 1] /= S_new; + pSPARC->ion_vel[count * 3 + 2] /= S_new; + count ++; + } + + //Update kinetic energy and kinetic stress based on new S + //pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + + /*for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + }*/ + + // Update SNOSE[0] to S_new + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_new; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// + + +} + + + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + else { + if (pSPARC->NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); + } + + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPTconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + else { + if (pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } + } + #endif + +} + + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const0, baro_const3, baro_const5; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, + temp_Pm_metric_tensor, 3, + pSPARC->metric_tensor, 3, + 0.0, temp_mat_1, 3); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, + temp_mat_1, 3, + temp_Pm_metric_tensor, 3, + 0.0, temp_mat_2, 3); + + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder: The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif + } +} + + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the quantities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE/pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + // Compute Ionic stress/pressure + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; + int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(9, sizeof(double)); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + printf("\n"); + printf("\n"); + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + // Print extended system parameters in case of NPH + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + // Print temperature + fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); + + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + + \ No newline at end of file diff --git a/src/md_fortran.c b/src/md_fortran.c new file mode 100644 index 00000000..5d722f9d --- /dev/null +++ b/src/md_fortran.c @@ -0,0 +1,3591 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include +#include +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + NPT_NP(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPH(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers + } +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 100; + + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + + if (rank == 0) { + // "w" creates a new file; "a" appends to an existing one. + pSPARC->fp_energy = fopen("MD_energies.log", "w"); + + if (pSPARC->fp_energy == NULL) { + fprintf(stderr, "Error: Could not open energy log file!\n"); + exit(EXIT_FAILURE); + } + + // Optional: Print a header to make the file readable in Excel/Python + fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", + "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); + fflush(pSPARC->fp_energy); + } + + fetch_MD_cell_ingredients(pSPARC, false); + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble\n"); + } + } + + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + fetch_MD_cell_ingredients(pSPARC, false); + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPH")){ + pSPARC->NPT_NP_qmass = 0; + } + + Calculate_ionic_stress(pSPARC); + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +*/ +void NPT_NP(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant +This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPH(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; + + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt(pSPARC->metric_tensor[0]); + pSPARC->range_y = sqrt(pSPARC->metric_tensor[4]); + pSPARC->range_z = sqrt(pSPARC->metric_tensor[8]); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat(pSPARC); + + //Update cell volume + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + + } + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate the velocity of cell lattice vectors + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } + + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + int count = 0; + + pSPARC->KE = 0.0; + int ityp, atm; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); + count ++; + } + } + pSPARC->KE = pSPARC->KE / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]); + pSPARC->temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); + +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + free(ion_vel_fractional); + + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); + + double total_internal_stress[9]; + for (int i = 0; i < 9; i++){ + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); + + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); + +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else { + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + double ktemp; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + // Calculating kinetic energy of ions + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b,1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp; + int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + + + double sumAllHamilTerms; + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } + } + #endif + } + + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa = 0.0; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + ktemp = pSPARC->kB * pSPARC->thermos_T; + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; + pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + } + + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; + + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) + for (int i = 0; i < 9; i++){ + temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 + } + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + } + + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + //Now write Intenal pressure, external pressure to a file + + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + // Calculate/Update the Hamiltonian (constant of motion) + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + //Optionall write all individual energy contributions to the Hamiltonian to an output file + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("AT THE END OF FIRST HALF\n"); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); + } + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], // snose(1) in Fortran is s + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure);; + } + } + + } + #endif + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); + + //Now impose the constraints on it + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + + //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints + // SPARC code was doing both these steps, reference code does not seem to do + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + ktemp = pSPARC->kB * pSPARC->thermos_T; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + /*if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + exit(EXIT_FAILURE); + }*/ + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp - S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + printf("%15.7f \n", S_new); + printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); + + + //Before updating cell parameters, compute atom positions in fractional coordinates + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); + count++; + } + + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + + //Update the Kinetic energy of the barostat based on new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / pSPARC->volumeCell / pSPARC->volumeCell; //Kinetic + + //Update the Potential energy of the barostat based on new metric tensor + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); + count++; + } + free(atom_pos_fractional); + + //Update atomic positions and restore ionic velocities + count = 0; + for(int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_new ); // + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_new ); // + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_new ); // + pSPARC->ion_vel[count * 3] /= pSPARC->SNOSE[0]; + pSPARC->ion_vel[count * 3 + 1] /= pSPARC->SNOSE[0]; + pSPARC->ion_vel[count * 3 + 2] /= pSPARC->SNOSE[0]; + count ++; + } + + //Update kinetic energy and kinetic stress based on new S + pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + } + + // Update SNOSE[0] to S_new + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_new; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// + + +} + + + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + else { + if (pSPARC->NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); + } + + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPTconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + else { + if (pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } + } + #endif + +} + + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const0, baro_const3, baro_const5; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, + temp_Pm_metric_tensor, 3, + pSPARC->metric_tensor, 3, + 0.0, temp_mat_1, 3); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, + temp_mat_1, 3, + temp_Pm_metric_tensor, 3, + 0.0, temp_mat_2, 3); + + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int ic1 = 0; ic1 < 9; ic1++){ + if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif + } +} + + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the quantities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE/pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + // Compute Ionic stress/pressure + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; + int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(9, sizeof(double)); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + printf("\n"); + printf("\n"); + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + // Print extended system parameters in case of NPH + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + // Print temperature + fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); + + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + + \ No newline at end of file diff --git a/src/md_working_on.c b/src/md_working_on.c new file mode 100644 index 00000000..25a438da --- /dev/null +++ b/src/md_working_on.c @@ -0,0 +1,3591 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include +#include +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + NPT_NP(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPH(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers + } +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 100; + + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + + if (rank == 0) { + // "w" creates a new file; "a" appends to an existing one. + pSPARC->fp_energy = fopen("MD_energies.log", "w"); + + if (pSPARC->fp_energy == NULL) { + fprintf(stderr, "Error: Could not open energy log file!\n"); + exit(EXIT_FAILURE); + } + + // Optional: Print a header to make the file readable in Excel/Python + fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", + "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); + fflush(pSPARC->fp_energy); + } + + fetch_MD_cell_ingredients(pSPARC, false); + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble\n"); + } + } + + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + fetch_MD_cell_ingredients(pSPARC, false); + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPH")){ + pSPARC->NPT_NP_qmass = 0; + } + + Calculate_ionic_stress(pSPARC); + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +*/ +void NPT_NP(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant +This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPH(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; + + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt(pSPARC->metric_tensor[0]); + pSPARC->range_y = sqrt(pSPARC->metric_tensor[4]); + pSPARC->range_z = sqrt(pSPARC->metric_tensor[8]); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat(pSPARC); + + //Update cell volume + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + + } + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate the velocity of cell lattice vectors + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } + + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + int count = 0; + + pSPARC->KE = 0.0; + int ityp, atm; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); + count ++; + } + } + pSPARC->KE = pSPARC->KE / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]); + pSPARC->temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); + +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + free(ion_vel_fractional); + + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); + + double total_internal_stress[9]; + for (int i = 0; i < 9; i++){ + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); + + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); + +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else { + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + double ktemp; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + // Calculating kinetic energy of ions + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b,1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp; + int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + + + double sumAllHamilTerms; + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } + } + #endif + } + + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa = 0.0; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + ktemp = pSPARC->kB * pSPARC->thermos_T; + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; + pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + } + + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; + + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) + for (int i = 0; i < 9; i++){ + temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + + cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 + } + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + } + + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + + double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + //Now write Intenal pressure, external pressure to a file + + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + // Calculate/Update the Hamiltonian (constant of motion) + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + //Optionall write all individual energy contributions to the Hamiltonian to an output file + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("AT THE END OF FIRST HALF\n"); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); + } + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], // snose(1) in Fortran is s + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure);; + } + } + + } + #endif + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); + + //Now impose the constraints on it + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + + //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints + // SPARC code was doing both these steps, reference code does not seem to do + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + ktemp = pSPARC->kB * pSPARC->thermos_T; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + /*if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + exit(EXIT_FAILURE); + }*/ + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp - S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + printf("%15.7f \n", S_new); + printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); + + + //Before updating cell parameters, compute atom positions in fractional coordinates + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); + count++; + } + + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + + //Update the Kinetic energy of the barostat based on new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / pSPARC->volumeCell / pSPARC->volumeCell; //Kinetic + + //Update the Potential energy of the barostat based on new metric tensor + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); + count++; + } + free(atom_pos_fractional); + + //Update atomic positions and restore ionic velocities + count = 0; + for(int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_new ); // + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_new ); // + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_new ); // + pSPARC->ion_vel[count * 3] /= S_new; + pSPARC->ion_vel[count * 3 + 1] /= S_new; + pSPARC->ion_vel[count * 3 + 2] /= S_new; + count ++; + } + + //Update kinetic energy and kinetic stress based on new S + pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + } + + // Update SNOSE[0] to S_new + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_new; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// + + +} + + + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + else { + if (pSPARC->NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); + } + + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPTconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + else { + if (pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } + } + #endif + +} + + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const0, baro_const3, baro_const5; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, + temp_Pm_metric_tensor, 3, + pSPARC->metric_tensor, 3, + 0.0, temp_mat_1, 3); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, + temp_mat_1, 3, + temp_Pm_metric_tensor, 3, + 0.0, temp_mat_2, 3); + + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int ic1 = 0; ic1 < 9; ic1++){ + if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif + } +} + + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the quantities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE/pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + // Compute Ionic stress/pressure + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; + int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(9, sizeof(double)); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + printf("\n"); + printf("\n"); + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + // Print extended system parameters in case of NPH + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + // Print temperature + fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); + + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + + \ No newline at end of file From 8f633bed05af666756e128131498c97f03e2ffb7 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Mon, 30 Mar 2026 14:32:16 -0400 Subject: [PATCH 23/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- ...rking_nice_but_hamiltonian_timings_issue.c | 3558 ++++++++++++++++ src/include/isddft.h | 6 +- src/include/md.h | 6 +- src/initialization.c | 17 +- src/md.c | 575 ++- src/md_fortran2.c | 3792 +++++++++++++++++ src/md_working_Cartesian_velocity.c | 3700 ++++++++++++++++ src/md_working_Cartesian_velocity.c.c | 3700 ++++++++++++++++ ..._but_velocity_fractional_cartesian_issue.c | 3700 ++++++++++++++++ 9 files changed, 18899 insertions(+), 155 deletions(-) create mode 100644 src/MD_working_nice_but_hamiltonian_timings_issue.c create mode 100644 src/md_fortran2.c create mode 100644 src/md_working_Cartesian_velocity.c create mode 100644 src/md_working_Cartesian_velocity.c.c create mode 100644 src/md_working_but_velocity_fractional_cartesian_issue.c diff --git a/src/MD_working_nice_but_hamiltonian_timings_issue.c b/src/MD_working_nice_but_hamiltonian_timings_issue.c new file mode 100644 index 00000000..719b7325 --- /dev/null +++ b/src/MD_working_nice_but_hamiltonian_timings_issue.c @@ -0,0 +1,3558 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include +#include +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + NPT_NP(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPH(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers + } +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 100; + + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + + if (rank == 0) { + // "w" creates a new file; "a" appends to an existing one. + pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); + + if (pSPARC->fp_energy == NULL) { + fprintf(stderr, "Error: Could not open energy log file!\n"); + exit(EXIT_FAILURE); + } + + // Optional: Print a header to make the file readable in Excel/Python + fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", + "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); + fflush(pSPARC->fp_energy); + } + + fetch_MD_cell_ingredients(pSPARC, false); + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble\n"); + } + } + + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + fetch_MD_cell_ingredients(pSPARC, false); + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPH")){ + pSPARC->NPT_NP_qmass = 0; + } + + Calculate_ionic_stress(pSPARC); + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +*/ +void NPT_NP(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant +This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPH(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; + + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat(pSPARC); + + //Update cell volume + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + + } + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate the velocity of cell lattice vectors + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } + + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + int count = 0; + + pSPARC->KE = 0.0; + int ityp, atm; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); + count ++; + } + } + + pSPARC->KE = pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); + pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); + +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + free(ion_vel_fractional); + + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); + + double total_internal_stress[9]; + for (int i = 0; i < 9; i++){ + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); + + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); + +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else { + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[0]; + double baro_const3 = 1.0 / baro_const1; + double ktemp; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + // Calculating kinetic energy of ions + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + double sumAllHamilTerms; + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp; + int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const3 = 1.0 / baro_const1; + + + + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// + + + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa = 0.0; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + ktemp = pSPARC->kB * pSPARC->thermos_T; + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; + pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + + /*pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + */ + } + + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; + + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) + for (int i = 0; i < 9; i++){ + temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 + } + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + + + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + + double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); + } + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], // snose(1) in Fortran is s + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure);; + } + } + + } + #endif + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); + + //Now impose the constraints on it + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints + // SPARC code was doing both these steps, reference code does not seem to do + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + ktemp = pSPARC->kB * pSPARC->thermos_T; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + /*if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + exit(EXIT_FAILURE); + }*/ + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp - S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + printf("%15.7f \n", S_new); + printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + //pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); + + + //Before updating cell parameters, compute atom positions in fractional coordinates + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); + count++; + } + + pSPARC->Snew = S_temp; + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + + //Update the Kinetic energy of the barostat based on new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / pSPARC->volumeCell / pSPARC->volumeCell; //Kinetic + + //Update the Potential energy of the barostat based on new metric tensor + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); + count++; + } + free(atom_pos_fractional); + + //Update atomic positions and restore ionic velocities + count = 0; + for(int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // + pSPARC->ion_vel[count * 3] /= S_temp; + pSPARC->ion_vel[count * 3 + 1] /= S_temp; + pSPARC->ion_vel[count * 3 + 2] /= S_temp; + count ++; + } + + //Update kinetic energy and kinetic stress based on new S + pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + } + + // Update SNOSE[0] to S_new + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_temp; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// + + +} + + + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + else { + if (pSPARC->NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); + } + + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPTconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + else { + if (pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } + } + #endif + +} + + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const0, baro_const3, baro_const5; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, + temp_Pm_metric_tensor, 3, + pSPARC->metric_tensor, 3, + 0.0, temp_mat_1, 3); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, + temp_mat_1, 3, + temp_Pm_metric_tensor, 3, + 0.0, temp_mat_2, 3); + + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int ic1 = 0; ic1 < 9; ic1++){ + if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif + } +} + + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the quantities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE/pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + // Compute Ionic stress/pressure + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; + int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(9, sizeof(double)); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + printf("\n"); + printf("\n"); + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + // Print extended system parameters in case of NPH + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + // Print temperature + fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); + + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + + \ No newline at end of file diff --git a/src/include/isddft.h b/src/include/isddft.h index 9bf68678..9d73e4a9 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -820,6 +820,7 @@ typedef struct _SPARC_OBJ{ double *ion_vel; // Ionic velocity double *ion_accel; // Ionic acceleration double *ion_forces_fractional; // Ionic forces in fractional coordinates + double *Pm_ion; double ion_T; // Ionic temperature double PE, KE, TE, TE_ext; // potential, kinetic and total energies respectively double kB; // Boltzmann constant @@ -903,6 +904,7 @@ typedef struct _SPARC_OBJ{ double external_stress_cartesian[9]; //external_stress matrix multiply reciprocal_metric_tensor double constraint_stress[9]; // Stress generated by constraining the evolution of cell lattice vectors lengths or angles double kinetic_stress[9]; + double kinetic_stress1[9]; double Kbaro; // kinetic energy of barostat variables double Ubaro; // potential energy of barostat variables double SNOSE[3]; // Thermostat control related information: Position variable of thermostat, velocity of thermostat, position variable at previous time step @@ -913,6 +915,8 @@ typedef struct _SPARC_OBJ{ double init_Hamil_NPT_NP; // initial Hamiltonian in NPT_NP ensemble double init_Hamil_NPH; // initial Hamiltonian in NPH ensemble double Snew; + double mean_internal_pressure; + double KE_save; //NPT_NP_specific double NPT_NP_qmass; // fictitious mass of thermostat (qmass) used in NPT_NP double NPT_NP_bmass; // fictitious mass of barostat (bmass) used in NPT_NP @@ -1459,7 +1463,7 @@ typedef struct _SPARC_INPUT_OBJ{ // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPH. int NPH_ANGLES; // whether to allow for changing angles in NPH, it can only be allowed (by setting to 1), when all lattice vectors can be rescaled using NPHscaleVecs: 1 2 3; // and when there are NO constraints in length confinement (so no input in NPHconstraintFlag) - + double pressure_external; // Externally applied hydrostatic pressure of NPT_NP or NPH system, UNIT on input file is GPa double stress_external[6]; // Externally applied anisotropic stress tensor (applied separately from pressure_external) for NPT_NP or NPH system, UNIT on input file is GPa //In NPT_NP and NPH, the target_stress[i] = pr_external+stress_external[i]; in contrast to NPT_NH where there is just target_pressure. diff --git a/src/include/md.h b/src/include/md.h index 824cbc71..1b2405f2 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -172,7 +172,8 @@ void transpose_and_add(double *matrix1); void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC); -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional); +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional, double *ion_vel_fractional); +void Calculate_Kinetic_stress_and_total_internal_pressure1(SPARC_OBJ *pSPARC, double *internal_stress_fractional); void compute_constraint_stress(SPARC_OBJ *pSPARC); @@ -183,7 +184,8 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl * @ brief: function to convert non cartesian to cartesian coordinates and velocities, from initialization.c */ void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord); - +void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC); +void Calculate_ionic_stress_linear_MD(SPARC_OBJ *pSPARC); /* * @brief: function to convert cartesian to non cartesian coordinates and velocities, from initialization.c */ diff --git a/src/initialization.c b/src/initialization.c index b7cb6375..0d5831c9 100644 --- a/src/initialization.c +++ b/src/initialization.c @@ -1572,7 +1572,7 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { } pSPARC->NPT_NP_bmass = pSPARC_Input->NPT_NP_bmass; pSPARC->NPT_NP_qmass = pSPARC_Input->NPT_NP_qmass; - pSPARC->NPH_bmass = pSPARC->NPH_bmass; + pSPARC->NPH_bmass = pSPARC_Input->NPH_bmass; pSPARC->NLCG_sigma = pSPARC_Input->NLCG_sigma; pSPARC->L_finit_stp = pSPARC_Input->L_finit_stp; pSPARC->L_maxmov = pSPARC_Input->L_maxmov; @@ -1915,6 +1915,21 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { printf(YEL"\nWARNING: This system is cuboidal. To get the best performance, please align the lattice vectors onto standard cartesian coordinate.\n" RESET); } } + + if (pSPARC->cell_typ == 0){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 1){ + pSPARC->cell_typ = 17; //change the default cell to triclinic as the change in angles in MD during NPT_NP ensemble would result in non-orthogonal cell if initially started with orthogonal + } + } + if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + if (pSPARC->NPH_ANGLES == 1){ + pSPARC->cell_typ = 17; //change the default cell to triclinic as the change in angles in MD during NPT_NP ensemble would result in non-orthogonal cell if initially started with orthogonal + } + } + } + + if (pSPARC->BC > 0) { if (pSPARC->BC == 1) { // dirichlet boundary diff --git a/src/md.c b/src/md.c index 375d9d2d..5c228b65 100644 --- a/src/md.c +++ b/src/md.c @@ -78,7 +78,7 @@ void main_MD(SPARC_OBJ *pSPARC) { } } } - + pSPARC->internal_pressure = 0; Calculate_Properties(pSPARC); //Calculate_electronicGroundState(pSPARC); Initialize_MD(pSPARC); @@ -312,18 +312,31 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); pSPARC->maxTimeIter = 100; - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); + printf("herere"); + exit(EXIT_FAILURE); + } + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + if(pSPARC->NPH_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); + printf("he1"); + exit(EXIT_FAILURE); + } + } + } if (rank == 0) { // "w" creates a new file; "a" appends to an existing one. @@ -339,9 +352,13 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); fflush(pSPARC->fp_energy); } - + pSPARC->KE_save = 0.0; fetch_MD_cell_ingredients(pSPARC, false); - + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ @@ -395,6 +412,11 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->maxTimeIter = 30; fetch_MD_cell_ingredients(pSPARC, false); + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } // pSPARC->thermos_Ti = pSPARC->elec_T; pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -1380,9 +1402,11 @@ void NPT_NP(SPARC_OBJ *pSPARC) { MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine NPT_NPH_main(pSPARC); // Reinitialize mesh size and related variables after changing size of cell @@ -1416,9 +1440,10 @@ void NPH(SPARC_OBJ *pSPARC) { MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } //NPT_NPH_main routine NPT_NPH_main(pSPARC); // Reinitialize mesh size and related variables after changing size of cell @@ -1455,6 +1480,120 @@ void transpose_and_add(double *matrix1){ matrix1[5] = matrix1[7] = s12; } +void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + int i, j, k; + + double TEMP_TOL = 1e-12; + // Construct LatUVec; + double mag; + for(i = 0; i < 3; i++){ + mag = sqrt(pow(pSPARC->full_lattice[3 * i], 2.0) + + pow(pSPARC->full_lattice[3 * i + 1], 2.0) + + pow(pSPARC->full_lattice[3 * i + 2], 2.0)); + pSPARC->LatUVec[3 * i] = pSPARC->full_lattice[3 * i]/mag; + pSPARC->LatUVec[3 * i + 1] = pSPARC->full_lattice[3 * i + 1]/mag; + pSPARC->LatUVec[3 * i + 2] = pSPARC->full_lattice[3 * i + 2]/mag; + } + + // determinant of 3x3 Jacobian + pSPARC->Jacbdet = 0.0; + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + if(i != j && j != k && k != i) + pSPARC->Jacbdet += ((i - j) * (j - k) * (k - i)/2) * pSPARC->LatUVec[3 * i] * pSPARC->LatUVec[3 * j + 1] * pSPARC->LatUVec[3 * k + 2]; + } + } + } + + if(pSPARC->Jacbdet <= 0){ + if(rank == 0) + printf("ERROR: Volume(det(jacobian)) %lf is <= 0\n", pSPARC->Jacbdet); + exit(EXIT_FAILURE); + } + + // transformation matrix for distance + for(i = 0; i < 9; i++) + pSPARC->metricT[i] = 0.0; + + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + pSPARC->metricT[3*i + j] += pSPARC->LatUVec[3*i + k] * pSPARC->LatUVec[3*j + k]; + } + } + } + + pSPARC->metricT[1] = 2 * pSPARC->metricT[1]; + pSPARC->metricT[2] = 2 * pSPARC->metricT[2]; + pSPARC->metricT[5] = 2 * pSPARC->metricT[5]; + + // transformation matrix for gradient + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + pSPARC->gradT[3*j + i] = (pSPARC->LatUVec[3 * ((j+1) % 3) + (i+1) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+2) % 3] - pSPARC->LatUVec[3 * ((j+1) % 3) + (i+2) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+1) % 3])/pSPARC->Jacbdet; + } + } + + // transformation matrix for laplacian + for(i = 0; i < 9; i++) + pSPARC->lapcT[i] = 0.0; + + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + pSPARC->lapcT[3*i + j] += pSPARC->gradT[3*i + k] * pSPARC->gradT[3*j + k]; + } + } + } + + /* Different cell types for laplacian */ + if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 11; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 12; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 13; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 14; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 15; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 16; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 17; +#ifdef DEBUG + if(!rank) + printf("\n\nCELL_TYP: %d\n\n",pSPARC->cell_typ); +#endif + /* transform the coefficiens of lapacian*/ + // int p, FDn = pSPARC->order/2; + // double dx_inv, dy_inv, dz_inv, dx2_inv, dy2_inv, dz2_inv; + // dx_inv = 1.0 / (pSPARC->delta_x); + // dy_inv = 1.0 / (pSPARC->delta_y); + // dz_inv = 1.0 / (pSPARC->delta_z); + // dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + // dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + // dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + // for (p = 0; p < FDn + 1; p++) { + // pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + // pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + // pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + // pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + // pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + // pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + // pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + // pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + // pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + // pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + // pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + // pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + // } + // TODO: Find maximum eigenvalue of Hamiltionian (= max. eigvalue of -0.5 lap) for non orthogonal periodic systems +} + /* Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix */ @@ -1464,7 +1603,7 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ double old_cell[9]; double new_cell[9]; - if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; @@ -1479,7 +1618,7 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ //Compute metric_tensor (G) in real-space (not reciprocal space) cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + // Cosine of Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma @@ -1513,10 +1652,24 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); //Update LatUVec, Jacbdet, metricT, gradT, lapcT - //Cart2nonCart_transformMat(pSPARC); + Cart2nonCart_transformMat_MD(pSPARC); + double det_metric_tensor = pSPARC->metric_tensor[0] * ( pSPARC->metric_tensor[4] * pSPARC->metric_tensor[8] - pSPARC->metric_tensor[7] * pSPARC->metric_tensor[5] ) + + pSPARC->metric_tensor[1] * ( pSPARC->metric_tensor[5] * pSPARC->metric_tensor[6] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[8] ) + + pSPARC->metric_tensor[2] * ( pSPARC->metric_tensor[3] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[6] * pSPARC->metric_tensor[4] ) ; + + double volume_check = sqrt(det_metric_tensor); //Update cell volume pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + if (rank ==0){ + printf("Volume from Jac %.6f for MD count %d \n",pSPARC->volumeCell, pSPARC->MDCount); + printf("Volume from metric tensor %.6f for MD count %d \n",volume_check, pSPARC->MDCount); + printf("Jacobian: %.6f for MD count %d \n",pSPARC->Jacbdet, pSPARC->MDCount); + printf(":LatUVec: \n"); + printf(" %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); @@ -1537,8 +1690,8 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; } @@ -1576,6 +1729,15 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + /*double temp_mat11[9]; + for (int i = 0; i < 9; i++){ + temp_mat11[i] = pSPARC->rotation_matrix[i]; + } + + pSPARC->rotation_matrix[1] = temp_mat11[3]; pSPARC->rotation_matrix[2] = temp_mat11[6]; pSPARC->rotation_matrix[5] = temp_mat11[7]; + pSPARC->rotation_matrix[3] = temp_mat11[1]; pSPARC->rotation_matrix[6] = temp_mat11[2]; pSPARC->rotation_matrix[7] = temp_mat11[5]; + */ + //Initiating cell lattice vectors velocity as zero for (int i = 0; i < 9; i++){ pSPARC->lattice_avg_velo[i] = 0.0; @@ -1619,76 +1781,98 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } } +void Calculate_ionic_stress_linear_MD(SPARC_OBJ *pSPARC){ + double *stress_i, *avgvel, mass_tot = 0.0; + stress_i = (double*) calloc(6, sizeof(double)); + avgvel = (double*) calloc(3, sizeof(double)); + int count, ityp, atm, j, k, index; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + avgvel[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + avgvel[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + avgvel[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + mass_tot += pSPARC->Mass[ityp]; + count += 1; + } + } + + for(j = 0; j < 3; j++) + avgvel[j] /= mass_tot; + + index = 0; + for(j = 0; j < 3; j++){ + for(k = j; k < 3; k++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + stress_i[index] = pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3 + j] - avgvel[j]) * (pSPARC->ion_vel[count * 3 + k] - avgvel[k]); + count++; + } + } + index++; + } + } + free(stress_i); + free(avgvel); +} void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - int count = 0; - + double vector[3]={0.0}; pSPARC->KE = 0.0; - int ityp, atm; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); - count ++; + + int count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, &pSPARC->Pm_ion[count*3], 1, 0.0, vector, 1); + pSPARC->KE += cblas_ddot(3, vector, 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + count++; } } - pSPARC->KE = pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); + pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); } -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional, double *ion_vel_fractional){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + double temp_mat_b[9]={0.0}; for (int i = 0; i < 9; i++){ pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 } - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - int count = 0; for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); count++; } } - free(ion_vel_fractional); + Calculate_ionic_stress_linear_MD(pSPARC); - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + pSPARC->kinetic_stress[0] = pSPARC->stress_i[0]; pSPARC->kinetic_stress[4] = pSPARC->stress_i[3]; pSPARC->kinetic_stress[8] = pSPARC->stress_i[5]; + pSPARC->kinetic_stress[1] = pSPARC->stress_i[1]; pSPARC->kinetic_stress[2] = pSPARC->stress_i[2]; pSPARC->kinetic_stress[3] = pSPARC->stress_i[1]; + pSPARC->kinetic_stress[5] = pSPARC->stress_i[4]; pSPARC->kinetic_stress[6] = pSPARC->stress_i[2]; pSPARC->kinetic_stress[7] = pSPARC->stress_i[4]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->kinetic_stress, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat_b, 3); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->reciprocal_lattice, 3, temp_mat_b, 3, 0.0, pSPARC->kinetic_stress, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); double total_internal_stress[9]; for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); } cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); @@ -1710,24 +1894,49 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ else { baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } - double baro_const2 = baro_const1 / pSPARC->SNOSE[0]; + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; double baro_const3 = 1.0 / baro_const1; - double ktemp; + double ktemp = pSPARC->kB * pSPARC->thermos_T; //Initialize empty temporary matrices and vectors double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// // Calculating kinetic energy of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); + + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, pSPARC->Mass[ityp], pSPARC->metric_tensor, 3, &ion_vel_fractional[count * 3], 1, 0.0, &pSPARC->Pm_ion[count * 3], 1); + count++; + } + } + free(ion_vel_fractional); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + pSPARC->KE_save = pSPARC->KE; // Calculating thermostat energies pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - ktemp = pSPARC->kB * pSPARC->thermos_T; pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - + // Calculating barostat energies cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); @@ -1743,14 +1952,16 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + double sumAllHamilTerms; sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - - + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 @@ -1778,7 +1989,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ void NPT_NPH_main(SPARC_OBJ *pSPARC) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp; + double ktemp = pSPARC->kB * pSPARC->thermos_T; int count; //Initialize empty temporary matrices and vectors @@ -1796,20 +2007,19 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { double baro_const3 = 1.0 / baro_const1; - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - + //Calculate_Ionic_particles_Kinetic_energy(pSPARC); + pSPARC->KE = pSPARC->KE_save; // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// double Sa = 0.0; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) if (pSPARC->NPT_NP_qmass > 0){ - ktemp = pSPARC->kB * pSPARC->thermos_T; - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; - pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; + pSPARC->SNOSE[1] += 0.5 * Sa * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; #ifdef DEBUG if (rank == 0) { printf("Sa is %12.9f\n", Sa); @@ -1818,26 +2028,25 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { #endif // Update the kinetic energy of the thermostat - /*pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - ktemp = pSPARC->kB * pSPARC->thermos_T; + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - */ + } // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; + internal_stress_cartesian[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3] - pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5] - pSPARC->stress_i[5]; + internal_stress_cartesian[1] = pSPARC->stress[1] - pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1] - pSPARC->stress_i[1]; + internal_stress_cartesian[5] = pSPARC->stress[4] - pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4] - pSPARC->stress_i[4]; //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) for (int i = 0; i < 9; i++){ temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b, 3); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { @@ -1845,7 +2054,21 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { for (int i = 0; i < 9; i++){ pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 } - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + + double *D2 = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); + count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + D2[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + D2[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + D2[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + count++; + } + } + + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, D2); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + free(D2); } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); @@ -1909,32 +2132,69 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds to Eqn. 18i in Hernandez paper - - double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + + double *D2C = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + D2C[count*3] = cblas_ddot(3, &pSPARC->full_lattice[0], 1, &pSPARC->forces[count*3], 1); + D2C[count*3 + 1] = cblas_ddot(3, &pSPARC->full_lattice[3], 1, &pSPARC->forces[count*3], 1); + D2C[count*3 + 2] = cblas_ddot(3, &pSPARC->full_lattice[6], 1, &pSPARC->forces[count*3], 1); + count++; } } + + // Eqn. 18i: momentum += 0.5 * dt * S * D2C + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], D2C, 1, pSPARC->Pm_ion, 1); //Update the kinetic energy of the Ionic particles Calculate_Ionic_particles_Kinetic_energy(pSPARC); - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + double *D2 = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); + + count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + D2[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + D2[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + D2[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + count++; + } + } + + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, D2); + free(D2); + + //Update Hamiltonian double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - #ifdef DEBUG + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; + // } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; + // } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + #ifdef DEBUG if (rank == 0) { printf("\n"); printf("rank %d", rank); @@ -1993,16 +2253,29 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { // Now we update/Step-up the momenta of the Ionic particles by dt/2 // This setup corresponds to Eqn. 18a in Hernandez paper + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], D2C, 1, pSPARC->Pm_ion, 1); + free(D2C); + + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + + double *ion_vel_fractional = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); + count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + ion_vel_fractional[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + ion_vel_fractional[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + ion_vel_fractional[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + count++; } } + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, ion_vel_fractional); + + // Now we update/Step-up the momenta of the barostat by dt/2 // This setup corresponds to Eqn. 18b in the Hernandez paper // This needs to be solved iteratively @@ -2037,36 +2310,22 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } } - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints - // SPARC code was doing both these steps, reference code does not seem to do - // Now we update/Step-up the momenta of the thermostat by dt/2 // This setup corresponds to Eqn. 18c in the Hernandez paper // Skip this step if doing NPH ensemble if (pSPARC->NPT_NP_qmass > 0){ double factor; - ktemp = pSPARC->kB * pSPARC->thermos_T; factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; #ifdef DEBUG if (rank == 0) printf("factor is %12.9f\n", factor); #endif - /*if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ if (rank == 0) - printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - exit(EXIT_FAILURE); - }*/ + printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + } pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); #ifdef DEBUG @@ -2091,7 +2350,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { //it iteration count exceeds max iteration counts, exit if (TimeIter > pSPARC->maxTimeIter){ printf("%15.7f \n", S_new); - printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); exit(1); } } @@ -2113,30 +2372,42 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - //pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); //Before updating cell parameters, compute atom positions in fractional coordinates double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + //double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); count = 0; for (int atm = 0; atm < pSPARC->n_atom; atm++){ atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); + //ion_vel_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count * 3 + 2]); + //ion_vel_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count * 3 + 2]); + //ion_vel_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count * 3 + 2]); + count++; } - pSPARC->Snew = S_temp; //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor fetch_MD_cell_ingredients(pSPARC, true); - //Update the Kinetic energy of the barostat based on new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / pSPARC->volumeCell / pSPARC->volumeCell; //Kinetic - //Update the Potential energy of the barostat based on new metric tensor + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + //Update the Kinetic energy of the barostat based on new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = atom_pos_fractional[count * 3] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3] / S_temp ); // + atom_pos_fractional[count * 3 + 1] = atom_pos_fractional[count * 3 + 1] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3 + 1] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3 + 1] / S_temp ); // + atom_pos_fractional[count * 3 + 2] = atom_pos_fractional[count * 3 + 2] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3 + 2] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3 + 2] / S_temp ); // + count++; + } // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) @@ -2145,16 +2416,19 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); count++; } free(atom_pos_fractional); - + free(ion_vel_fractional); //Update atomic positions and restore ionic velocities count = 0; for(int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // + //pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // + //pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // + //pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // pSPARC->ion_vel[count * 3] /= S_temp; pSPARC->ion_vel[count * 3 + 1] /= S_temp; pSPARC->ion_vel[count * 3 + 2] /= S_temp; @@ -2162,10 +2436,11 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); + pSPARC->KE_save = pSPARC->KE; for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; + pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); } // Update SNOSE[0] to S_new @@ -2454,18 +2729,18 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl //Initialize some useful constants bool converged; // determine whether the iteration converges or not int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence + const double tolerance = 1e-12; // tolerance criterion for checking convergence double baro_const0, baro_const3, baro_const5; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } else{ baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } @@ -2481,17 +2756,9 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, - temp_Pm_metric_tensor, 3, - pSPARC->metric_tensor, 3, - 0.0, temp_mat_1, 3); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, - temp_mat_1, 3, - temp_Pm_metric_tensor, 3, - 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); - //Transpose temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; @@ -2501,7 +2768,7 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl // Eqn. 18b Hernandez paper for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } @@ -2511,8 +2778,8 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl //Check convergence converged = true; - for (int ic1 = 0; ic1 < 9; ic1++){ - if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ + for (int i = 0; i < 9; i++){ + if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ converged = false; break; } @@ -2781,7 +3048,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE/pSPARC->n_atom); fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); @@ -2876,6 +3143,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // Print Statistical properties fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":PRES_INT: %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA); fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); @@ -2921,8 +3189,8 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); } pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE/pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); + + pSPARC->TE = (pSPARC->PE + pSPARC->KE/pSPARC->n_atom); // Extended System (Ionic system + Thermostat) energy if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; @@ -2931,10 +3199,13 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) Calculate_ionic_stress(pSPARC); + if ((pSPARC->MDCount == 0) && (pSPARC->RestartFlag != 1)) { + pSPARC->mean_internal_pressure = (pSPARC->pres-pSPARC->pres_i); + } // Calculate_stress(pSPARC); #ifdef DEBUG // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old; int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; mean_Te_old = pSPARC->mean_elec_T; mean_Ti_old = pSPARC->mean_ion_T; @@ -2943,6 +3214,8 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { mean_PE_old = pSPARC->mean_PE; mean_U_old = pSPARC->mean_U; mean_Eent_old = pSPARC->mean_Entropy; + mean_internal_pressure_old = pSPARC->mean_internal_pressure; + pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; @@ -3555,4 +3828,4 @@ void Rename_restart(SPARC_OBJ *pSPARC) { rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); } - \ No newline at end of file + diff --git a/src/md_fortran2.c b/src/md_fortran2.c new file mode 100644 index 00000000..9ab26976 --- /dev/null +++ b/src/md_fortran2.c @@ -0,0 +1,3792 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include +#include +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + pSPARC->internal_pressure = 0; + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + NPT_NP(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPH(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers + } +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 100; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); + printf("herere"); + exit(EXIT_FAILURE); + } + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + if(pSPARC->NPH_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); + printf("he1"); + exit(EXIT_FAILURE); + } + } + } + + if (rank == 0) { + // "w" creates a new file; "a" appends to an existing one. + pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); + + if (pSPARC->fp_energy == NULL) { + fprintf(stderr, "Error: Could not open energy log file!\n"); + exit(EXIT_FAILURE); + } + + // Optional: Print a header to make the file readable in Excel/Python + fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", + "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); + fflush(pSPARC->fp_energy); + } + pSPARC->KE_save = 0.0; + fetch_MD_cell_ingredients(pSPARC, false); + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble\n"); + } + } + + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + fetch_MD_cell_ingredients(pSPARC, false); + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPH")){ + pSPARC->NPT_NP_qmass = 0; + } + + Calculate_ionic_stress(pSPARC); + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +*/ +void NPT_NP(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant +This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPH(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + +void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + int i, j, k; + + double TEMP_TOL = 1e-12; + // Construct LatUVec; + double mag; + for(i = 0; i < 3; i++){ + mag = sqrt(pow(pSPARC->full_lattice[3 * i], 2.0) + + pow(pSPARC->full_lattice[3 * i + 1], 2.0) + + pow(pSPARC->full_lattice[3 * i + 2], 2.0)); + pSPARC->LatUVec[3 * i] = pSPARC->full_lattice[3 * i]/mag; + pSPARC->LatUVec[3 * i + 1] = pSPARC->full_lattice[3 * i + 1]/mag; + pSPARC->LatUVec[3 * i + 2] = pSPARC->full_lattice[3 * i + 2]/mag; + } + + // determinant of 3x3 Jacobian + pSPARC->Jacbdet = 0.0; + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + if(i != j && j != k && k != i) + pSPARC->Jacbdet += ((i - j) * (j - k) * (k - i)/2) * pSPARC->LatUVec[3 * i] * pSPARC->LatUVec[3 * j + 1] * pSPARC->LatUVec[3 * k + 2]; + } + } + } + + if(pSPARC->Jacbdet <= 0){ + if(rank == 0) + printf("ERROR: Volume(det(jacobian)) %lf is <= 0\n", pSPARC->Jacbdet); + exit(EXIT_FAILURE); + } + + // transformation matrix for distance + for(i = 0; i < 9; i++) + pSPARC->metricT[i] = 0.0; + + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + pSPARC->metricT[3*i + j] += pSPARC->LatUVec[3*i + k] * pSPARC->LatUVec[3*j + k]; + } + } + } + + pSPARC->metricT[1] = 2 * pSPARC->metricT[1]; + pSPARC->metricT[2] = 2 * pSPARC->metricT[2]; + pSPARC->metricT[5] = 2 * pSPARC->metricT[5]; + + // transformation matrix for gradient + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + pSPARC->gradT[3*j + i] = (pSPARC->LatUVec[3 * ((j+1) % 3) + (i+1) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+2) % 3] - pSPARC->LatUVec[3 * ((j+1) % 3) + (i+2) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+1) % 3])/pSPARC->Jacbdet; + } + } + + // transformation matrix for laplacian + for(i = 0; i < 9; i++) + pSPARC->lapcT[i] = 0.0; + + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + pSPARC->lapcT[3*i + j] += pSPARC->gradT[3*i + k] * pSPARC->gradT[3*j + k]; + } + } + } + + /* Different cell types for laplacian */ + if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 11; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 12; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 13; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 14; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 15; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 16; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 17; +#ifdef DEBUG + if(!rank) + printf("\n\nCELL_TYP: %d\n\n",pSPARC->cell_typ); +#endif + /* transform the coefficiens of lapacian*/ + // int p, FDn = pSPARC->order/2; + // double dx_inv, dy_inv, dz_inv, dx2_inv, dy2_inv, dz2_inv; + // dx_inv = 1.0 / (pSPARC->delta_x); + // dy_inv = 1.0 / (pSPARC->delta_y); + // dz_inv = 1.0 / (pSPARC->delta_z); + // dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + // dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + // dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + // for (p = 0; p < FDn + 1; p++) { + // pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + // pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + // pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + // pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + // pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + // pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + // pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + // pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + // pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + // pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + // pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + // pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + // } + // TODO: Find maximum eigenvalue of Hamiltionian (= max. eigvalue of -0.5 lap) for non orthogonal periodic systems +} + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Cosine of Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; + + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat_MD(pSPARC); + + double det_metric_tensor = pSPARC->metric_tensor[0] * ( pSPARC->metric_tensor[4] * pSPARC->metric_tensor[8] - pSPARC->metric_tensor[7] * pSPARC->metric_tensor[5] ) + + pSPARC->metric_tensor[1] * ( pSPARC->metric_tensor[5] * pSPARC->metric_tensor[6] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[8] ) + + pSPARC->metric_tensor[2] * ( pSPARC->metric_tensor[3] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[6] * pSPARC->metric_tensor[4] ) ; + + double volume_check = sqrt(det_metric_tensor); + //Update cell volume + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + if (rank ==0){ + printf("Volume from Jac %.6f for MD count %d \n",pSPARC->volumeCell, pSPARC->MDCount); + printf("Volume from metric tensor %.6f for MD count %d \n",volume_check, pSPARC->MDCount); + printf("Jacobian: %.6f for MD count %d \n",pSPARC->Jacbdet, pSPARC->MDCount); + printf(":LatUVec: \n"); + printf(" %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + + } + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + /*double temp_mat11[9]; + for (int i = 0; i < 9; i++){ + temp_mat11[i] = pSPARC->rotation_matrix[i]; + } + + pSPARC->rotation_matrix[1] = temp_mat11[3]; pSPARC->rotation_matrix[2] = temp_mat11[6]; pSPARC->rotation_matrix[5] = temp_mat11[7]; + pSPARC->rotation_matrix[3] = temp_mat11[1]; pSPARC->rotation_matrix[6] = temp_mat11[2]; pSPARC->rotation_matrix[7] = temp_mat11[5]; + */ + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate the velocity of cell lattice vectors + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } + + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double vector[3]={0.0}; + pSPARC->KE = 0.0; + + int count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, &pSPARC->Pm_ion[count*3], 1, 0.0, vector, 1); + pSPARC->KE += cblas_ddot(3, vector, 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + count++; + } + } + + pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); + pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); + +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional, double *ion_vel_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); + + double total_internal_stress[9]; + for (int i = 0; i < 9; i++){ + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); + + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); + +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else { + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + double ktemp = pSPARC->kB * pSPARC->thermos_T; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + // Calculating kinetic energy of ions + + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); + + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, pSPARC->Mass[ityp], pSPARC->metric_tensor, 3, &ion_vel_fractional[count * 3], 1, 0.0, &pSPARC->Pm_ion[count * 3], 1); + count++; + } + } + free(ion_vel_fractional); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + pSPARC->KE_save = pSPARC->KE; + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + + + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + + double sumAllHamilTerms; + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp = pSPARC->kB * pSPARC->thermos_T; + int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const3 = 1.0 / baro_const1; + + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// + + //Calculate_Ionic_particles_Kinetic_energy(pSPARC); + pSPARC->KE = pSPARC->KE_save; + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa = 0.0; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; + pSPARC->SNOSE[1] += 0.5 * Sa * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + } + + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3] - pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5] - pSPARC->stress_i[5]; + internal_stress_cartesian[1] = pSPARC->stress[1] - pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1] - pSPARC->stress_i[1]; + internal_stress_cartesian[5] = pSPARC->stress[4] - pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4] - pSPARC->stress_i[4]; + + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) + for (int i = 0; i < 9; i++){ + temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b, 3); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 + } + + double *D2 = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); + count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + D2[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + D2[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + D2[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + count++; + } + } + + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, D2); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + free(D2); + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + + double *D2C = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); + count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + D2C[count*3] = cblas_ddot(3, &pSPARC->full_lattice[0], 1, &pSPARC->forces[count*3], 1); + D2C[count*3 + 1] = cblas_ddot(3, &pSPARC->full_lattice[3], 1, &pSPARC->forces[count*3], 1); + D2C[count*3 + 2] = cblas_ddot(3, &pSPARC->full_lattice[6], 1, &pSPARC->forces[count*3], 1); + count++; + } + } + + // Eqn. 18i: momentum += 0.5 * dt * S * D2C + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], D2C, 1, pSPARC->Pm_ion, 1); + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + + double *D2 = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); + + count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + D2[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + D2[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + D2[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + count++; + } + } + + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, D2); + free(D2); + + //Update Hamiltonian + double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; + // } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; + // } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); + } + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], // snose(1) in Fortran is s + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure);; + } + } + + } + #endif + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], D2C, 1, pSPARC->Pm_ion, 1); + free(D2C); + + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + + double *ion_vel_fractional = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); + + count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + ion_vel_fractional[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + ion_vel_fractional[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + ion_vel_fractional[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + count++; + } + } + + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, ion_vel_fractional); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); + + //Now impose the constraints on it + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + } + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp - S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + printf("%15.7f \n", S_new); + printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); + + + //Before updating cell parameters, compute atom positions in fractional coordinates + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + //double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); + //ion_vel_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count * 3 + 2]); + //ion_vel_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count * 3 + 2]); + //ion_vel_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count * 3 + 2]); + + count++; + } + pSPARC->Snew = S_temp; + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + + //Update the Potential energy of the barostat based on new metric tensor + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + //Update the Kinetic energy of the barostat based on new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic + + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = atom_pos_fractional[count * 3] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3] / S_temp ); // + atom_pos_fractional[count * 3 + 1] = atom_pos_fractional[count * 3 + 1] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3 + 1] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3 + 1] / S_temp ); // + atom_pos_fractional[count * 3 + 2] = atom_pos_fractional[count * 3 + 2] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3 + 2] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3 + 2] / S_temp ); // + count++; + } + + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); + count++; + } + free(atom_pos_fractional); + free(ion_vel_fractional); + //Update atomic positions and restore ionic velocities + count = 0; + for(int atm = 0; atm < pSPARC->n_atom; atm++){ + //pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // + //pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // + //pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // + pSPARC->ion_vel[count * 3] /= S_temp; + pSPARC->ion_vel[count * 3 + 1] /= S_temp; + pSPARC->ion_vel[count * 3 + 2] /= S_temp; + count ++; + } + + //Update kinetic energy and kinetic stress based on new S + pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); + pSPARC->KE_save = pSPARC->KE; + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); + } + + // Update SNOSE[0] to S_new + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_temp; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// + + +} + + + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + else { + if (pSPARC->NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); + } + + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPTconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + else { + if (pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } + } + #endif + +} + + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-12; // tolerance criterion for checking convergence + double baro_const0, baro_const3, baro_const5; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + + } + + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif + } +} + + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE/pSPARC->n_atom); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":PRES_INT: %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the quantities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + + pSPARC->TE = (pSPARC->PE + pSPARC->KE/pSPARC->n_atom); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + // Compute Ionic stress/pressure + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + + if ((pSPARC->MDCount == 0) && (pSPARC->RestartFlag != 1)) { + pSPARC->mean_internal_pressure = (pSPARC->pres-pSPARC->pres_i); + } + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old; + int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + mean_internal_pressure_old = pSPARC->mean_internal_pressure; + pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(9, sizeof(double)); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + printf("\n"); + printf("\n"); + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + // Print extended system parameters in case of NPH + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + // Print temperature + fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); + + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + + diff --git a/src/md_working_Cartesian_velocity.c b/src/md_working_Cartesian_velocity.c new file mode 100644 index 00000000..e71c1114 --- /dev/null +++ b/src/md_working_Cartesian_velocity.c @@ -0,0 +1,3700 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include +#include +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + NPT_NP(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPH(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers + } +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 100; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); + printf("herere"); + exit(EXIT_FAILURE); + } + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + if(pSPARC->NPH_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); + printf("he1"); + exit(EXIT_FAILURE); + } + } + } + + + + if (rank == 0) { + // "w" creates a new file; "a" appends to an existing one. + pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); + + if (pSPARC->fp_energy == NULL) { + fprintf(stderr, "Error: Could not open energy log file!\n"); + exit(EXIT_FAILURE); + } + + // Optional: Print a header to make the file readable in Excel/Python + fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", + "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); + fflush(pSPARC->fp_energy); + } + + fetch_MD_cell_ingredients(pSPARC, false); + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble\n"); + } + } + + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + fetch_MD_cell_ingredients(pSPARC, false); + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPH")){ + pSPARC->NPT_NP_qmass = 0; + } + + Calculate_ionic_stress(pSPARC); + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +*/ +void NPT_NP(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant +This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPH(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; + + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat(pSPARC); + + //Update cell volume + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + + } + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + /*double temp_mat11[9]; + for (int i = 0; i < 9; i++){ + temp_mat11[i] = pSPARC->rotation_matrix[i]; + } + + pSPARC->rotation_matrix[1] = temp_mat11[3]; pSPARC->rotation_matrix[2] = temp_mat11[6]; pSPARC->rotation_matrix[5] = temp_mat11[7]; + pSPARC->rotation_matrix[3] = temp_mat11[1]; pSPARC->rotation_matrix[6] = temp_mat11[2]; pSPARC->rotation_matrix[7] = temp_mat11[5]; + */ + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate the velocity of cell lattice vectors + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } + + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double avgvel[3] = {0.0, 0.0, 0.0}; + double mass_tot = 0.0; + int count, ityp, atm; + + // Compute center-of-mass velocity + count = 0; + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + avgvel[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + avgvel[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + avgvel[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + mass_tot += pSPARC->Mass[ityp]; + count++; + } + } + avgvel[0] /= mass_tot; + avgvel[1] /= mass_tot; + avgvel[2] /= mass_tot; + + double vx, vy, vz; + pSPARC->KE = 0.0; + count = 0; + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + vx = pSPARC->ion_vel[count * 3] - avgvel[0]; + vy = pSPARC->ion_vel[count * 3 + 1] - avgvel[1]; + vz = pSPARC->ion_vel[count * 3 + 2] - avgvel[2]; + pSPARC->KE += pSPARC->Mass[ityp] * (vx*vx + vy*vy + vz*vz); + count++; + } + } + + pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); + //pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); + count ++; + } + } + + pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + free(ion_vel_fractional); + + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); + + double total_internal_stress[9]; + for (int i = 0; i < 9; i++){ + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); + + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); + +} + + + +void Calculate_Kinetic_stress_and_total_internal_pressure1(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress1[i] = 0.0; //Initialize kinetic stress to 0 + } + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress1[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress1[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress1[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress1[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress1[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress1[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + free(ion_vel_fractional); + + pSPARC->kinetic_stress1[3] = pSPARC->kinetic_stress1[1]; + pSPARC->kinetic_stress1[6] = pSPARC->kinetic_stress1[2]; + pSPARC->kinetic_stress1[7] = pSPARC->kinetic_stress1[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress1, 1); + +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else { + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[0]; + double baro_const3 = 1.0 / baro_const1; + double ktemp = pSPARC->kB * pSPARC->thermos_T; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + // Calculating kinetic energy of ions + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + + + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + + double sumAllHamilTerms; + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp = pSPARC->kB * pSPARC->thermos_T; + int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const3 = 1.0 / baro_const1; + + + + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// + + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + //Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa = 0.0; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; + pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + } + + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; + + internal_stress_cartesian[0] = pSPARC->stress[0]-pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3]-pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5]-pSPARC->stress_i[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]-pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1]-pSPARC->stress_i[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]-pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4]-pSPARC->stress_i[4]; + + + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) + for (int i = 0; i < 9; i++){ + temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b, 3); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + for (int i = 0; i < 9; i++){ + internal_stress_fractional[i] += pSPARC->kinetic_stress1[i]; + } + + for (int i = 0; i < 9; i++){ + internal_stress_fractional[i] *= 0.5 ; + } + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 + } + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + //cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + //Update Hamiltonian + double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); + } + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], // snose(1) in Fortran is s + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure);; + } + } + + } + #endif + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + + //Update the kinetic energy and kinetic stress of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); + + //Now impose the constraints on it + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + //Calculate_Ionic_particles_Kinetic_energy(pSPARC); + //cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + //temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + //temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + //temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + //pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + } + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp - S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + printf("%15.7f \n", S_new); + printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); + + + //Before updating cell parameters, compute atom positions in fractional coordinates + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); + ion_vel_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count * 3 + 2]); + ion_vel_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count * 3 + 2]); + ion_vel_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count * 3 + 2]); + + count++; + } + + pSPARC->Snew = S_temp; + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + + //Update the Potential energy of the barostat based on new metric tensor + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + //Update the Kinetic energy of the barostat based on new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic + + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); + + count++; + } + free(atom_pos_fractional); + free(ion_vel_fractional); + //Update atomic positions and restore ionic velocities + count = 0; + for(int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // + pSPARC->ion_vel[count * 3] /= S_temp; + pSPARC->ion_vel[count * 3 + 1] /= S_temp; + pSPARC->ion_vel[count * 3 + 2] /= S_temp; + count ++; + } + + //Update kinetic energy and kinetic stress based on new S + pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); + } + + // Update SNOSE[0] to S_new + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_temp; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// + + +} + + + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + else { + if (pSPARC->NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); + } + + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPTconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + else { + if (pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } + } + #endif + +} + + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-12; // tolerance criterion for checking convergence + double baro_const0, baro_const3, baro_const5; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif + } +} + + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the quantities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE/pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + // Compute Ionic stress/pressure + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; + int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(9, sizeof(double)); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + printf("\n"); + printf("\n"); + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + // Print extended system parameters in case of NPH + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + // Print temperature + fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); + + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + + diff --git a/src/md_working_Cartesian_velocity.c.c b/src/md_working_Cartesian_velocity.c.c new file mode 100644 index 00000000..e71c1114 --- /dev/null +++ b/src/md_working_Cartesian_velocity.c.c @@ -0,0 +1,3700 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include +#include +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + NPT_NP(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPH(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers + } +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 100; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); + printf("herere"); + exit(EXIT_FAILURE); + } + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + if(pSPARC->NPH_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); + printf("he1"); + exit(EXIT_FAILURE); + } + } + } + + + + if (rank == 0) { + // "w" creates a new file; "a" appends to an existing one. + pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); + + if (pSPARC->fp_energy == NULL) { + fprintf(stderr, "Error: Could not open energy log file!\n"); + exit(EXIT_FAILURE); + } + + // Optional: Print a header to make the file readable in Excel/Python + fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", + "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); + fflush(pSPARC->fp_energy); + } + + fetch_MD_cell_ingredients(pSPARC, false); + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble\n"); + } + } + + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + fetch_MD_cell_ingredients(pSPARC, false); + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPH")){ + pSPARC->NPT_NP_qmass = 0; + } + + Calculate_ionic_stress(pSPARC); + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +*/ +void NPT_NP(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant +This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPH(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; + + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat(pSPARC); + + //Update cell volume + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + + } + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + /*double temp_mat11[9]; + for (int i = 0; i < 9; i++){ + temp_mat11[i] = pSPARC->rotation_matrix[i]; + } + + pSPARC->rotation_matrix[1] = temp_mat11[3]; pSPARC->rotation_matrix[2] = temp_mat11[6]; pSPARC->rotation_matrix[5] = temp_mat11[7]; + pSPARC->rotation_matrix[3] = temp_mat11[1]; pSPARC->rotation_matrix[6] = temp_mat11[2]; pSPARC->rotation_matrix[7] = temp_mat11[5]; + */ + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate the velocity of cell lattice vectors + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } + + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double avgvel[3] = {0.0, 0.0, 0.0}; + double mass_tot = 0.0; + int count, ityp, atm; + + // Compute center-of-mass velocity + count = 0; + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + avgvel[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + avgvel[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + avgvel[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + mass_tot += pSPARC->Mass[ityp]; + count++; + } + } + avgvel[0] /= mass_tot; + avgvel[1] /= mass_tot; + avgvel[2] /= mass_tot; + + double vx, vy, vz; + pSPARC->KE = 0.0; + count = 0; + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + vx = pSPARC->ion_vel[count * 3] - avgvel[0]; + vy = pSPARC->ion_vel[count * 3 + 1] - avgvel[1]; + vz = pSPARC->ion_vel[count * 3 + 2] - avgvel[2]; + pSPARC->KE += pSPARC->Mass[ityp] * (vx*vx + vy*vy + vz*vz); + count++; + } + } + + pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); + //pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); + count ++; + } + } + + pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + free(ion_vel_fractional); + + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); + + double total_internal_stress[9]; + for (int i = 0; i < 9; i++){ + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); + + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); + +} + + + +void Calculate_Kinetic_stress_and_total_internal_pressure1(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress1[i] = 0.0; //Initialize kinetic stress to 0 + } + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress1[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress1[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress1[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress1[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress1[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress1[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + free(ion_vel_fractional); + + pSPARC->kinetic_stress1[3] = pSPARC->kinetic_stress1[1]; + pSPARC->kinetic_stress1[6] = pSPARC->kinetic_stress1[2]; + pSPARC->kinetic_stress1[7] = pSPARC->kinetic_stress1[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress1, 1); + +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else { + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[0]; + double baro_const3 = 1.0 / baro_const1; + double ktemp = pSPARC->kB * pSPARC->thermos_T; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + // Calculating kinetic energy of ions + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + + + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + + double sumAllHamilTerms; + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp = pSPARC->kB * pSPARC->thermos_T; + int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const3 = 1.0 / baro_const1; + + + + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// + + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + //Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa = 0.0; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; + pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + } + + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; + + internal_stress_cartesian[0] = pSPARC->stress[0]-pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3]-pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5]-pSPARC->stress_i[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]-pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1]-pSPARC->stress_i[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]-pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4]-pSPARC->stress_i[4]; + + + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) + for (int i = 0; i < 9; i++){ + temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b, 3); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + for (int i = 0; i < 9; i++){ + internal_stress_fractional[i] += pSPARC->kinetic_stress1[i]; + } + + for (int i = 0; i < 9; i++){ + internal_stress_fractional[i] *= 0.5 ; + } + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 + } + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + //cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + //Update Hamiltonian + double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); + } + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], // snose(1) in Fortran is s + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure);; + } + } + + } + #endif + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + + //Update the kinetic energy and kinetic stress of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); + + //Now impose the constraints on it + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + //Calculate_Ionic_particles_Kinetic_energy(pSPARC); + //cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + //temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + //temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + //temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + //pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + } + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp - S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + printf("%15.7f \n", S_new); + printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); + + + //Before updating cell parameters, compute atom positions in fractional coordinates + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); + ion_vel_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count * 3 + 2]); + ion_vel_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count * 3 + 2]); + ion_vel_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count * 3 + 2]); + + count++; + } + + pSPARC->Snew = S_temp; + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + + //Update the Potential energy of the barostat based on new metric tensor + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + //Update the Kinetic energy of the barostat based on new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic + + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); + + count++; + } + free(atom_pos_fractional); + free(ion_vel_fractional); + //Update atomic positions and restore ionic velocities + count = 0; + for(int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // + pSPARC->ion_vel[count * 3] /= S_temp; + pSPARC->ion_vel[count * 3 + 1] /= S_temp; + pSPARC->ion_vel[count * 3 + 2] /= S_temp; + count ++; + } + + //Update kinetic energy and kinetic stress based on new S + pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); + } + + // Update SNOSE[0] to S_new + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_temp; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// + + +} + + + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + else { + if (pSPARC->NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); + } + + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPTconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + else { + if (pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } + } + #endif + +} + + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-12; // tolerance criterion for checking convergence + double baro_const0, baro_const3, baro_const5; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif + } +} + + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the quantities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE/pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + // Compute Ionic stress/pressure + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; + int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(9, sizeof(double)); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + printf("\n"); + printf("\n"); + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + // Print extended system parameters in case of NPH + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + // Print temperature + fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); + + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + + diff --git a/src/md_working_but_velocity_fractional_cartesian_issue.c b/src/md_working_but_velocity_fractional_cartesian_issue.c new file mode 100644 index 00000000..e71c1114 --- /dev/null +++ b/src/md_working_but_velocity_fractional_cartesian_issue.c @@ -0,0 +1,3700 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include +#include +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + NPT_NP(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPH(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers + } +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 100; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); + printf("herere"); + exit(EXIT_FAILURE); + } + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + if(pSPARC->NPH_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); + printf("he1"); + exit(EXIT_FAILURE); + } + } + } + + + + if (rank == 0) { + // "w" creates a new file; "a" appends to an existing one. + pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); + + if (pSPARC->fp_energy == NULL) { + fprintf(stderr, "Error: Could not open energy log file!\n"); + exit(EXIT_FAILURE); + } + + // Optional: Print a header to make the file readable in Excel/Python + fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", + "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); + fflush(pSPARC->fp_energy); + } + + fetch_MD_cell_ingredients(pSPARC, false); + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble\n"); + } + } + + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->maxTimeIter = 30; + + fetch_MD_cell_ingredients(pSPARC, false); + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPH")){ + pSPARC->NPT_NP_qmass = 0; + } + + Calculate_ionic_stress(pSPARC); + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +*/ +void NPT_NP(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant +This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPH(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine + NPT_NPH_main(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + #endif +} + + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; + + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat(pSPARC); + + //Update cell volume + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + + } + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + /*double temp_mat11[9]; + for (int i = 0; i < 9; i++){ + temp_mat11[i] = pSPARC->rotation_matrix[i]; + } + + pSPARC->rotation_matrix[1] = temp_mat11[3]; pSPARC->rotation_matrix[2] = temp_mat11[6]; pSPARC->rotation_matrix[5] = temp_mat11[7]; + pSPARC->rotation_matrix[3] = temp_mat11[1]; pSPARC->rotation_matrix[6] = temp_mat11[2]; pSPARC->rotation_matrix[7] = temp_mat11[5]; + */ + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate the velocity of cell lattice vectors + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } + + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double avgvel[3] = {0.0, 0.0, 0.0}; + double mass_tot = 0.0; + int count, ityp, atm; + + // Compute center-of-mass velocity + count = 0; + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + avgvel[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + avgvel[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + avgvel[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + mass_tot += pSPARC->Mass[ityp]; + count++; + } + } + avgvel[0] /= mass_tot; + avgvel[1] /= mass_tot; + avgvel[2] /= mass_tot; + + double vx, vy, vz; + pSPARC->KE = 0.0; + count = 0; + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + vx = pSPARC->ion_vel[count * 3] - avgvel[0]; + vy = pSPARC->ion_vel[count * 3 + 1] - avgvel[1]; + vz = pSPARC->ion_vel[count * 3 + 2] - avgvel[2]; + pSPARC->KE += pSPARC->Mass[ityp] * (vx*vx + vy*vy + vz*vz); + count++; + } + } + + pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); + //pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); + count ++; + } + } + + pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + free(ion_vel_fractional); + + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); + + double total_internal_stress[9]; + for (int i = 0; i < 9; i++){ + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); + + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); + +} + + + +void Calculate_Kinetic_stress_and_total_internal_pressure1(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress1[i] = 0.0; //Initialize kinetic stress to 0 + } + + if (ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + // Handle error (e.g., exit or return) + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); + ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); + count++; + } + } + + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress1[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress1[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress1[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress1[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress1[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress1[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + count++; + } + } + + free(ion_vel_fractional); + + pSPARC->kinetic_stress1[3] = pSPARC->kinetic_stress1[1]; + pSPARC->kinetic_stress1[6] = pSPARC->kinetic_stress1[2]; + pSPARC->kinetic_stress1[7] = pSPARC->kinetic_stress1[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress1, 1); + +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else { + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[0]; + double baro_const3 = 1.0 / baro_const1; + double ktemp = pSPARC->kB * pSPARC->thermos_T; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + // Calculating kinetic energy of ions + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + + + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + + double sumAllHamilTerms; + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp = pSPARC->kB * pSPARC->thermos_T; + int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const3 = 1.0 / baro_const1; + + + + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// + + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + //Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa = 0.0; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; + pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + } + + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; + + internal_stress_cartesian[0] = pSPARC->stress[0]-pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3]-pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5]-pSPARC->stress_i[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]-pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1]-pSPARC->stress_i[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]-pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4]-pSPARC->stress_i[4]; + + + //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) + for (int i = 0; i < 9; i++){ + temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b, 3); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + for (int i = 0; i < 9; i++){ + internal_stress_fractional[i] += pSPARC->kinetic_stress1[i]; + } + + for (int i = 0; i < 9; i++){ + internal_stress_fractional[i] *= 0.5 ; + } + + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 + } + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + //cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + //Update Hamiltonian + double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); + } + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + if (pSPARC->fp_energy != NULL) { + fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", + pSPARC->KE, + pSPARC->Etot, + pSPARC->Kbaro + pSPARC->Ubaro, + pSPARC->Kther + pSPARC->Uther, + sumAllHamilTerms, + pSPARC->Hamiltonian_NPT_NP, + pSPARC->SNOSE[0], // snose(1) in Fortran is s + pSPARC->init_Hamil_NPT_NP, + pSPARC->volumeCell, + pSPARC->temperature, + pSPARC->internal_pressure);; + } + } + + } + #endif + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } + + //Update the kinetic energy and kinetic stress of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); + + //Now impose the constraints on it + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + //Calculate_Ionic_particles_Kinetic_energy(pSPARC); + //cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + //temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + //temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + //temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + //pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + } + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp - S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + printf("%15.7f \n", S_new); + printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); + + + //Before updating cell parameters, compute atom positions in fractional coordinates + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); + atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); + ion_vel_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count * 3 + 2]); + ion_vel_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count * 3 + 2]); + ion_vel_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count * 3 + 2]); + + count++; + } + + pSPARC->Snew = S_temp; + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + + //Update the Potential energy of the barostat based on new metric tensor + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + //Update the Kinetic energy of the barostat based on new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic + + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + count = 0; + for (int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); + pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); + pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); + + count++; + } + free(atom_pos_fractional); + free(ion_vel_fractional); + //Update atomic positions and restore ionic velocities + count = 0; + for(int atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // + pSPARC->ion_vel[count * 3] /= S_temp; + pSPARC->ion_vel[count * 3 + 1] /= S_temp; + pSPARC->ion_vel[count * 3 + 2] /= S_temp; + count ++; + } + + //Update kinetic energy and kinetic stress based on new S + pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); + } + + // Update SNOSE[0] to S_new + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_temp; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// + + +} + + + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + else { + if (pSPARC->NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); + } + + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPTconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + else { + if (pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } + } + #endif + +} + + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-12; // tolerance criterion for checking convergence + double baro_const0, baro_const3, baro_const5; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; + } + + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif + } +} + + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the quantities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE/pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + // Compute Ionic stress/pressure + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; + int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(9, sizeof(double)); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + printf("\n"); + printf("\n"); + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + // Print extended system parameters in case of NPH + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + // Print temperature + fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); + + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, + // compute scale from x is enough + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + + From f0f7e253a2d955a7c75dbad1dcfccba963841fce Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Mon, 30 Mar 2026 18:55:51 -0400 Subject: [PATCH 24/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/md.h | 2 +- src/md.c | 136 ++++++++++++++++------------------------------- 2 files changed, 46 insertions(+), 92 deletions(-) diff --git a/src/include/md.h b/src/include/md.h index 1b2405f2..21405dfd 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -185,7 +185,7 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl */ void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord); void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC); -void Calculate_ionic_stress_linear_MD(SPARC_OBJ *pSPARC); + /* * @brief: function to convert cartesian to non cartesian coordinates and velocities, from initialization.c */ diff --git a/src/md.c b/src/md.c index 5c228b65..440bcf9c 100644 --- a/src/md.c +++ b/src/md.c @@ -340,7 +340,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { if (rank == 0) { // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); + pSPARC->fp_energy = fopen("MD_energies_NPH2.log", "w"); if (pSPARC->fp_energy == NULL) { fprintf(stderr, "Error: Could not open energy log file!\n"); @@ -1653,23 +1653,23 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ //Update LatUVec, Jacbdet, metricT, gradT, lapcT Cart2nonCart_transformMat_MD(pSPARC); + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - double det_metric_tensor = pSPARC->metric_tensor[0] * ( pSPARC->metric_tensor[4] * pSPARC->metric_tensor[8] - pSPARC->metric_tensor[7] * pSPARC->metric_tensor[5] ) - + pSPARC->metric_tensor[1] * ( pSPARC->metric_tensor[5] * pSPARC->metric_tensor[6] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[8] ) - + pSPARC->metric_tensor[2] * ( pSPARC->metric_tensor[3] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[6] * pSPARC->metric_tensor[4] ) ; + // double det_metric_tensor = pSPARC->metric_tensor[0] * ( pSPARC->metric_tensor[4] * pSPARC->metric_tensor[8] - pSPARC->metric_tensor[7] * pSPARC->metric_tensor[5] ) + // + pSPARC->metric_tensor[1] * ( pSPARC->metric_tensor[5] * pSPARC->metric_tensor[6] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[8] ) + // + pSPARC->metric_tensor[2] * ( pSPARC->metric_tensor[3] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[6] * pSPARC->metric_tensor[4] ) ; - double volume_check = sqrt(det_metric_tensor); - //Update cell volume - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - if (rank ==0){ - printf("Volume from Jac %.6f for MD count %d \n",pSPARC->volumeCell, pSPARC->MDCount); - printf("Volume from metric tensor %.6f for MD count %d \n",volume_check, pSPARC->MDCount); - printf("Jacobian: %.6f for MD count %d \n",pSPARC->Jacbdet, pSPARC->MDCount); - printf(":LatUVec: \n"); - printf(" %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } + // double volume_check = sqrt(det_metric_tensor); + // //Update cell volume + // if (rank ==0){ + // printf("Volume from Jac %.6f for MD count %d \n",pSPARC->volumeCell, pSPARC->MDCount); + // printf("Volume from metric tensor %.6f for MD count %d \n",volume_check, pSPARC->MDCount); + // printf("Jacobian: %.6f for MD count %d \n",pSPARC->Jacbdet, pSPARC->MDCount); + // printf(":LatUVec: \n"); + // printf(" %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + // , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + // , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + // } // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); @@ -1781,41 +1781,6 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } } -void Calculate_ionic_stress_linear_MD(SPARC_OBJ *pSPARC){ - double *stress_i, *avgvel, mass_tot = 0.0; - stress_i = (double*) calloc(6, sizeof(double)); - avgvel = (double*) calloc(3, sizeof(double)); - int count, ityp, atm, j, k, index; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - avgvel[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - avgvel[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - avgvel[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - mass_tot += pSPARC->Mass[ityp]; - count += 1; - } - } - - for(j = 0; j < 3; j++) - avgvel[j] /= mass_tot; - - index = 0; - for(j = 0; j < 3; j++){ - for(k = j; k < 3; k++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - stress_i[index] = pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3 + j] - avgvel[j]) * (pSPARC->ion_vel[count * 3 + k] - avgvel[k]); - count++; - } - } - index++; - } - } - free(stress_i); - free(avgvel); -} void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ int rank; @@ -1843,8 +1808,6 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, dou int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double temp_mat_b[9]={0.0}; - for (int i = 0; i < 9; i++){ pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 } @@ -1852,21 +1815,19 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, dou int count = 0; for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; count++; } } - Calculate_ionic_stress_linear_MD(pSPARC); - - pSPARC->kinetic_stress[0] = pSPARC->stress_i[0]; pSPARC->kinetic_stress[4] = pSPARC->stress_i[3]; pSPARC->kinetic_stress[8] = pSPARC->stress_i[5]; - pSPARC->kinetic_stress[1] = pSPARC->stress_i[1]; pSPARC->kinetic_stress[2] = pSPARC->stress_i[2]; pSPARC->kinetic_stress[3] = pSPARC->stress_i[1]; - pSPARC->kinetic_stress[5] = pSPARC->stress_i[4]; pSPARC->kinetic_stress[6] = pSPARC->stress_i[2]; pSPARC->kinetic_stress[7] = pSPARC->stress_i[4]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->kinetic_stress, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat_b, 3); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->reciprocal_lattice, 3, temp_mat_b, 3, 0.0, pSPARC->kinetic_stress, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); @@ -2145,7 +2106,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds to Eqn. 18i in Hernandez paper - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + //cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); double *D2C = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); count = 0; @@ -2183,15 +2144,15 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { //Update Hamiltonian double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; - // } + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; + } pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper } else { - // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; - // } + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms ; + } pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } #ifdef DEBUG @@ -2232,9 +2193,9 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { pSPARC->Kbaro + pSPARC->Ubaro, pSPARC->Kther + pSPARC->Uther, sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, + pSPARC->Hamiltonian_NPH, pSPARC->SNOSE[0], // snose(1) in Fortran is s - pSPARC->init_Hamil_NPT_NP, + pSPARC->init_Hamil_NPH, pSPARC->volumeCell, pSPARC->temperature, pSPARC->internal_pressure);; @@ -2384,10 +2345,6 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); - //ion_vel_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count * 3 + 2]); - //ion_vel_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count * 3 + 2]); - //ion_vel_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count * 3 + 2]); - count++; } pSPARC->Snew = S_temp; @@ -2426,9 +2383,6 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { //Update atomic positions and restore ionic velocities count = 0; for(int atm = 0; atm < pSPARC->n_atom; atm++){ - //pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // - //pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // - //pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // pSPARC->ion_vel[count * 3] /= S_temp; pSPARC->ion_vel[count * 3 + 1] /= S_temp; pSPARC->ion_vel[count * 3 + 2] /= S_temp; @@ -3003,7 +2957,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); else fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha \n"); } if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ @@ -3013,12 +2967,12 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); } else { fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); } if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha \n"); } if(pSPARC->Calc_stress == 1){ fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); @@ -3057,11 +3011,11 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); } if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH); if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); // Print atomic position if(pSPARC->PrintAtomPosFlag){ @@ -3088,7 +3042,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ fprintf(output_md,":ANGLES:\n"); fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); if (pSPARC->Flag_latvec_scale == 0){ @@ -3133,9 +3087,9 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma double pres_ig = 0.0; pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i) * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig * CONST_HA_BOHR3_GPA); // Ideal Gas } From 462d062e70453cb66738519ea134fbf927b68bb7 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Mon, 30 Mar 2026 20:41:47 -0400 Subject: [PATCH 25/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 195 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 111 insertions(+), 84 deletions(-) diff --git a/src/md.c b/src/md.c index 440bcf9c..c879ef39 100644 --- a/src/md.c +++ b/src/md.c @@ -356,8 +356,8 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { fetch_MD_cell_ingredients(pSPARC, false); pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + exit(EXIT_FAILURE); } pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -405,20 +405,20 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; + //pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; //This is computed in function: 'fetch_MD_cell_ingredients_restart' below pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; + pSPARC->maxTimeIter = 100; - fetch_MD_cell_ingredients(pSPARC, false); + pSPARC->KE_save = 0.0; + fetch_MD_cell_ingredients_restart(pSPARC); pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) + fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); + exit(EXIT_FAILURE); } - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -435,7 +435,12 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { if(strcmpi(pSPARC->MDMeth,"NPH")){ pSPARC->NPT_NP_qmass = 0; + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; } + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! Calculate_ionic_stress(pSPARC); } @@ -1597,6 +1602,42 @@ void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC) { /* Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix */ + +void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat_MD(pSPARC); + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + +} + void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -1703,7 +1744,6 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } - // Calculate the inverse of lattice-vector double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; double S_inv[9] = {0}; @@ -1726,17 +1766,8 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; + //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell@Rotation_matrix.T = old_cell; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - /*double temp_mat11[9]; - for (int i = 0; i < 9; i++){ - temp_mat11[i] = pSPARC->rotation_matrix[i]; - } - - pSPARC->rotation_matrix[1] = temp_mat11[3]; pSPARC->rotation_matrix[2] = temp_mat11[6]; pSPARC->rotation_matrix[5] = temp_mat11[7]; - pSPARC->rotation_matrix[3] = temp_mat11[1]; pSPARC->rotation_matrix[6] = temp_mat11[2]; pSPARC->rotation_matrix[7] = temp_mat11[5]; - */ //Initiating cell lattice vectors velocity as zero for (int i = 0; i < 9; i++){ @@ -1804,7 +1835,7 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ } -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional, double *ion_vel_fractional){ +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *ion_vel_fractional){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -1831,15 +1862,6 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, dou cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - double total_internal_stress[9]; - for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); - } @@ -1869,8 +1891,8 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) + fprintf(stderr, "Error: Memory allocation failed for ion_vel_fractional array in the NPT_NP_and_NPH_init_hamiltonian function.\n"); + exit(EXIT_FAILURE); } int count = 0; @@ -1890,6 +1912,10 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ count++; } } + + // Calculate kinetic energy and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, ion_vel_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + free(ion_vel_fractional); Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper pSPARC->KE_save = pSPARC->KE; @@ -1913,12 +1939,10 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - + double sumAllHamilTerms; sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper @@ -1935,9 +1959,13 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ } pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } - - + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// + + //Initialize constraint stress to 0 + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; + } } /* @@ -2009,29 +2037,6 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b, 3); cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 - } - - double *D2 = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - D2[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - D2[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - D2[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - count++; - } - } - - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, D2); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - free(D2); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); @@ -2140,6 +2145,13 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { // Calculate internal pressure and kinetic stress Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, D2); free(D2); + + double total_internal_stress[9]; + for (int i = 0; i < 9; i++){ + total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); //Update Hamiltonian double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; @@ -3414,63 +3426,78 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter + // fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + // , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + // , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep + fprintf(mdout,":SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice if (pSPARC->Flag_latvec_scale == 0){ fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] + , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] + , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); } else { fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] + , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] + , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); } + fprintf(mdout,":RECIPROCAL_LATTICE: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->reciprocal_lattice[0], pSPARC->reciprocal_lattice[1], pSPARC->reciprocal_lattice[2] + , pSPARC->reciprocal_lattice[3], pSPARC->reciprocal_lattice[4], pSPARC->reciprocal_lattice[5] + , pSPARC->reciprocal_lattice[6], pSPARC->reciprocal_lattice[7], pSPARC->reciprocal_lattice[8]); fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); + fprintf(mdout,":ROTATION_MATRIX: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] + , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] + , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 ,pSPARC->stress_external[3] * 29421.02648438959 ,pSPARC->stress_external[4] * 29421.02648438959 ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); } // Print extended system parameters in case of NPH if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter + // fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + // , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + // , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice if (pSPARC->Flag_latvec_scale == 0){ fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] + , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] + , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); } else { fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] + , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] + , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); } + fprintf(mdout,":RECIPROCAL_LATTICE: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->reciprocal_lattice[0], pSPARC->reciprocal_lattice[1], pSPARC->reciprocal_lattice[2] + , pSPARC->reciprocal_lattice[3], pSPARC->reciprocal_lattice[4], pSPARC->reciprocal_lattice[5] + , pSPARC->reciprocal_lattice[6], pSPARC->reciprocal_lattice[7], pSPARC->reciprocal_lattice[8]); fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); + fprintf(mdout,":ROTATION_MATRIX: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] + , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] + , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 + ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 ,pSPARC->stress_external[3] * 29421.02648438959 ,pSPARC->stress_external[4] * 29421.02648438959 ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); } // Print temperature fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); From 0482385304d4633b325a34503360ba6bcf746ac7 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Mon, 30 Mar 2026 21:06:32 -0400 Subject: [PATCH 26/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 68 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/src/md.c b/src/md.c index c879ef39..eda3394c 100644 --- a/src/md.c +++ b/src/md.c @@ -3425,12 +3425,12 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter // fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] // , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] // , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep - fprintf(mdout,":SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep + fprintf(mdout,":NPT_NP_SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep + fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice @@ -3468,7 +3468,7 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { // fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] // , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] // , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + fprintf(mdout,":LATTICE_AVG_VELOCITY: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice if (pSPARC->Flag_latvec_scale == 0){ @@ -3482,9 +3482,6 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); } - fprintf(mdout,":RECIPROCAL_LATTICE: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->reciprocal_lattice[0], pSPARC->reciprocal_lattice[1], pSPARC->reciprocal_lattice[2] - , pSPARC->reciprocal_lattice[3], pSPARC->reciprocal_lattice[4], pSPARC->reciprocal_lattice[5] - , pSPARC->reciprocal_lattice[6], pSPARC->reciprocal_lattice[7], pSPARC->reciprocal_lattice[8]); fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); fprintf(mdout,":ROTATION_MATRIX: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] @@ -3655,40 +3652,49 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); else if (strcmpi(str,":NPT_NP_BMASS:") == 0) fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + else if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[0]); + else if (strcmpi(str,":NPT_NP_SNOSE[1]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[1]); + else if (strcmpi(str,":NPT_NP_SNOSE[2]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[2]); + else if (strcmpi(str,":LATTICE_AVG_VELOCITY:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[0]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[1]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[2]); + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[3]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[4]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[5]); + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[6]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[7]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[8]); + + } else if (strcmpi(str,":CELL:") == 0) { + fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); + } else if (strcmpi(str,":LatUVec:") == 0) { + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); + } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); fscanf(rst_fp, "%*[^\n]\n"); - double nowRange_x, nowRange_y, nowRange_z; pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; + pSPARC->range_x = pSPARC->initialLatVecLength[0]*pSPARC->latvec_scale_x; + pSPARC->range_y = pSPARC->initialLatVecLength[1]*pSPARC->latvec_scale_y; + pSPARC->range_z = pSPARC->initialLatVecLength[2]*pSPARC->latvec_scale_z; + + } else if (strcmpi(str,":LatVec:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); + fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); + fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); + + } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[6]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[7]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[8]); } else if (strcmpi(str,":TTHRMI(K):") == 0) fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); else if (strcmpi(str,":TARGET_PRESSURE:") == 0) fscanf(rst_fp,"%lf", &pSPARC->prtarget); - else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) + else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); } } From effea3e2e3965abdfc24a0d8c25ad7c60c79d862 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 31 Mar 2026 12:02:49 -0400 Subject: [PATCH 27/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 147 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 120 insertions(+), 27 deletions(-) diff --git a/src/md.c b/src/md.c index eda3394c..80e8b785 100644 --- a/src/md.c +++ b/src/md.c @@ -313,10 +313,16 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { MPI_Comm_rank(MPI_COMM_WORLD, &rank); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 100; + if (pSPARC->Flag_latvec_scale == 1){ + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else{ + pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; + } + + pSPARC->maxTimeIter = 100; if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ if(pSPARC->NPT_NP_bmass == 0.0) { @@ -406,10 +412,16 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { MPI_Comm_rank(MPI_COMM_WORLD, &rank); //pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; //This is computed in function: 'fetch_MD_cell_ingredients_restart' below - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 100; + + if (pSPARC->Flag_latvec_scale == 1){ + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else{ + pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; + } + pSPARC->maxTimeIter = 100; pSPARC->KE_save = 0.0; fetch_MD_cell_ingredients_restart(pSPARC); @@ -1607,6 +1619,8 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double old_cell[9]; + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; //Compute Cell lattice vectors (scaled by LATVEC scale) @@ -1633,6 +1647,30 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); // Now computing reciprocal metric tensor, cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); @@ -1775,7 +1813,7 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } } - //If updating the cell, then also calculate the velocity of cell lattice vectors + //If updating the cell, then also calculate the velocity of cell lattice vectors (only useful in 1st MD step (start afresh or restart)) else { double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; @@ -3445,21 +3483,19 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); } - fprintf(mdout,":RECIPROCAL_LATTICE: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->reciprocal_lattice[0], pSPARC->reciprocal_lattice[1], pSPARC->reciprocal_lattice[2] - , pSPARC->reciprocal_lattice[3], pSPARC->reciprocal_lattice[4], pSPARC->reciprocal_lattice[5] - , pSPARC->reciprocal_lattice[6], pSPARC->reciprocal_lattice[7], pSPARC->reciprocal_lattice[8]); fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); fprintf(mdout,":ROTATION_MATRIX: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * 29421.02648438959); + fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * 29421.02648438959 + ,pSPARC->stress_external[1] * 29421.02648438959 + ,pSPARC->stress_external[2] * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); } // Print extended system parameters in case of NPH @@ -3488,12 +3524,13 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * 29421.02648438959); + fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * 29421.02648438959 + ,pSPARC->stress_external[1] * 29421.02648438959 + ,pSPARC->stress_external[2] * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); } // Print temperature @@ -3662,13 +3699,16 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[0]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[1]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[2]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[3]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[4]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[5]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[6]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[7]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[8]); - + } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); } else if (strcmpi(str,":CELL:") == 0) { fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); + } else if (strcmpi(str,":LatUVec:") == 0) { fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); + } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); fscanf(rst_fp, "%*[^\n]\n"); @@ -3692,11 +3732,64 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if (strcmpi(str,":TTHRMI(K):") == 0) fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); + else if (strcmpi(str,":EXTERNAL_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->pressure_external); + else if (strcmpi(str,":EXTERNAL_STRESS:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->stress_external[0]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[1]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[2]); + fscanf(rst_fp,"%lf", &pSPARC->stress_external[3]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[4]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[5]); + } else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); } + if (strcmpi(pSPARC->MDMeth,"NPH") == 0) { + if (strcmpi(str,":NPH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPH_bmass); + else if (strcmpi(str,":LATTICE_AVG_VELOCITY:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[0]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[1]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[2]); + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[3]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[4]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[5]); + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[6]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[7]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[8]); + } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); + } else if (strcmpi(str,":CELL:") == 0) { + fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); + + } else if (strcmpi(str,":LatUVec:") == 0) { + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); + + } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->range_x = pSPARC->initialLatVecLength[0]*pSPARC->latvec_scale_x; + pSPARC->range_y = pSPARC->initialLatVecLength[1]*pSPARC->latvec_scale_y; + pSPARC->range_z = pSPARC->initialLatVecLength[2]*pSPARC->latvec_scale_z; + + } else if (strcmpi(str,":LatVec:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); + fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); + fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); + + } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[6]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[7]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[8]); + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":EXTERNAL_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->pressure_external); + else if (strcmpi(str,":EXTERNAL_STRESS:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->stress_external[0]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[1]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[2]); + fscanf(rst_fp,"%lf", &pSPARC->stress_external[3]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[4]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[5]); + } + else if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); + } } fclose(rst_fp); From 5d8c2fbd69105369c9c3aac77c8d5649d478ee9e Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 31 Mar 2026 12:18:29 -0400 Subject: [PATCH 28/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 92 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 17 deletions(-) diff --git a/src/md.c b/src/md.c index 80e8b785..d5fa7be4 100644 --- a/src/md.c +++ b/src/md.c @@ -3463,11 +3463,8 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - // fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - // , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - // , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter fprintf(mdout,":NPT_NP_SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep + fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] @@ -3483,7 +3480,6 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); fprintf(mdout,":ROTATION_MATRIX: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] @@ -3518,7 +3514,6 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); fprintf(mdout,":ROTATION_MATRIX: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] @@ -3825,12 +3820,44 @@ void RestartMD(SPARC_OBJ *pSPARC) { else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if (pSPARC->Flag_latvec_scale == 0){ + MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + if (pSPARC->Flag_latvec_scale == 1){ + MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Pack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if (pSPARC->Flag_latvec_scale == 0){ + MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + if (pSPARC->Flag_latvec_scale == 1){ + MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } } @@ -3876,15 +3903,46 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); } else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if (pSPARC->Flag_latvec_scale == 0){ + MPI_Unpack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + if (pSPARC->Flag_latvec_scale == 1){ + MPI_Unpack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + MPI_Unpack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Unpack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if (pSPARC->Flag_latvec_scale == 0){ + MPI_Unpack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + if (pSPARC->Flag_latvec_scale == 1){ + MPI_Unpack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + MPI_Unpack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } } From 1b728470a634dbc03ccc0228f7c7813738ff5d04 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 31 Mar 2026 12:31:55 -0400 Subject: [PATCH 29/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/md.c b/src/md.c index d5fa7be4..086967e6 100644 --- a/src/md.c +++ b/src/md.c @@ -3575,7 +3575,10 @@ void RestartMD(SPARC_OBJ *pSPARC) { l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52)) * sizeof(double); } else { l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); From eba54b2ec21cadca049f26b9b41881fee638ec78 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 31 Mar 2026 12:45:30 -0400 Subject: [PATCH 30/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 84 ++++++-------------------------------------------------- 1 file changed, 9 insertions(+), 75 deletions(-) diff --git a/src/md.c b/src/md.c index 086967e6..f0907293 100644 --- a/src/md.c +++ b/src/md.c @@ -147,10 +147,8 @@ void main_MD(SPARC_OBJ *pSPARC) { NVK_G(pSPARC); else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - NPT_NP(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPT_NP_and_NPH(pSPARC); else{ if (!rank){ printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); @@ -365,8 +363,8 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); exit(EXIT_FAILURE); } - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 } @@ -380,8 +378,6 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ if (!rank) { printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); @@ -401,11 +397,8 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - pSPARC->thermos_Ti = pSPARC->ion_T; pSPARC->thermos_T = pSPARC->thermos_Ti; - - } else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart int rank; @@ -763,7 +756,6 @@ void Leapfrog_part1(SPARC_OBJ *pSPARC) { pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; count ++; } - } /* @@ -791,7 +783,6 @@ void Leapfrog_part2(SPARC_OBJ *pSPARC) { } - /** @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. It is based on the implementation in ABINIT (ionmov=12) @@ -799,7 +790,6 @@ void Leapfrog_part2(SPARC_OBJ *pSPARC) { void NVK_G(SPARC_OBJ *pSPARC) { // Calculate velocity at next half time step Calc_vel1_G(pSPARC); - // Charge extrapolation (for better rho_guess) elecDensExtrapolation(pSPARC); // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain @@ -1408,54 +1398,18 @@ void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ /* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -*/ -void NPT_NP(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant -This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant. +Also performs NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant. NPH in this scheme is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference for NPT_NP and NPH: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Additional Reference for NPH: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." Physical Review B 55.14 (1997): 8733. */ -void NPH(SPARC_OBJ *pSPARC) { +void NPT_NP_and_NPH(SPARC_OBJ *pSPARC) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - //Calculate initial hamitonian if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { @@ -1474,11 +1428,10 @@ void NPH(SPARC_OBJ *pSPARC) { //Calculate_electronicGroundState(pSPARC); pSPARC->elecgs_Count++; #ifdef DEBUG - if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); #endif } - /* Computes transpose of a matrix and adds it to the original matrix */ @@ -1652,7 +1605,6 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ old_cell[i] = pSPARC->full_lattice[i]; } - // Calculate the inverse of lattice-vector double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; double S_inv[9] = {0}; @@ -1734,22 +1686,6 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ Cart2nonCart_transformMat_MD(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - // double det_metric_tensor = pSPARC->metric_tensor[0] * ( pSPARC->metric_tensor[4] * pSPARC->metric_tensor[8] - pSPARC->metric_tensor[7] * pSPARC->metric_tensor[5] ) - // + pSPARC->metric_tensor[1] * ( pSPARC->metric_tensor[5] * pSPARC->metric_tensor[6] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[8] ) - // + pSPARC->metric_tensor[2] * ( pSPARC->metric_tensor[3] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[6] * pSPARC->metric_tensor[4] ) ; - - // double volume_check = sqrt(det_metric_tensor); - // //Update cell volume - // if (rank ==0){ - // printf("Volume from Jac %.6f for MD count %d \n",pSPARC->volumeCell, pSPARC->MDCount); - // printf("Volume from metric tensor %.6f for MD count %d \n",volume_check, pSPARC->MDCount); - // printf("Jacobian: %.6f for MD count %d \n",pSPARC->Jacbdet, pSPARC->MDCount); - // printf(":LatUVec: \n"); - // printf(" %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - // , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - // , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - // } - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); @@ -1781,7 +1717,6 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ old_cell[i] = pSPARC->full_lattice[i]; } - // Calculate the inverse of lattice-vector double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; double S_inv[9] = {0}; @@ -1899,7 +1834,6 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, dou pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - } From 19272b9e2bd6684f9b3773ff38ffc320bacca018 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 31 Mar 2026 12:52:08 -0400 Subject: [PATCH 31/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 89 ++++++++++++++++++-------------------------------------- 1 file changed, 28 insertions(+), 61 deletions(-) diff --git a/src/md.c b/src/md.c index f0907293..26649e72 100644 --- a/src/md.c +++ b/src/md.c @@ -2388,13 +2388,9 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - - } - - void compute_constraint_stress(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -2660,7 +2656,6 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } - void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -2681,13 +2676,11 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl } - //Initialize empty temporary matrices and vectors double temp_mat[9]; double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - for (int i = 0; i < 9; i++){ temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; } @@ -3754,12 +3747,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ MPI_Pack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); @@ -3768,33 +3756,25 @@ void RestartMD(SPARC_OBJ *pSPARC) { if (pSPARC->Flag_latvec_scale == 0){ MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } - if (pSPARC->Flag_latvec_scale == 1){ + else if (pSPARC->Flag_latvec_scale == 1){ MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Pack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if (pSPARC->Flag_latvec_scale == 0){ - MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } - if (pSPARC->Flag_latvec_scale == 1){ - MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Pack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } - MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } } @@ -3839,47 +3819,34 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); if (pSPARC->Flag_latvec_scale == 0){ MPI_Unpack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } - if (pSPARC->Flag_latvec_scale == 1){ + else if (pSPARC->Flag_latvec_scale == 1){ MPI_Unpack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } MPI_Unpack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Unpack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Unpack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Unpack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Unpack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if (pSPARC->Flag_latvec_scale == 0){ - MPI_Unpack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } - if (pSPARC->Flag_latvec_scale == 1){ - MPI_Unpack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Unpack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } - MPI_Unpack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } } From a9a79a3660dc1c8592fc45b4f14bb174ab1ae6bf Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 31 Mar 2026 12:57:01 -0400 Subject: [PATCH 32/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/md.c b/src/md.c index 26649e72..96cce019 100644 --- a/src/md.c +++ b/src/md.c @@ -3821,31 +3821,31 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); if (pSPARC->Flag_latvec_scale == 0){ - MPI_Unpack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->LatUVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); } else if (pSPARC->Flag_latvec_scale == 1){ - MPI_Unpack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->LatVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); } - MPI_Unpack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->rotation_matrix, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->pressure_external, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->stress_external, 6, MPI_DOUBLE, MPI_COMM_WORLD); if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[0], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[1], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[2], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Unpack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Unpack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPH_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); } } } From 28bee5080751bec02122219e7737d0b3413d34b6 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 31 Mar 2026 19:45:47 -0400 Subject: [PATCH 33/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 8 +- src/include/md.h | 10 +- src/md.c | 593 +++++++++++++++++-------------------------- 3 files changed, 246 insertions(+), 365 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index 9d73e4a9..598814dc 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -819,8 +819,8 @@ typedef struct _SPARC_OBJ{ /* MD/relax options */ double *ion_vel; // Ionic velocity double *ion_accel; // Ionic acceleration - double *ion_forces_fractional; // Ionic forces in fractional coordinates - double *Pm_ion; + double *Pm_ion; // Ionic momenta + double *ion_vel_fractional // Ionic velocity in fractional coordinates double ion_T; // Ionic temperature double PE, KE, TE, TE_ext; // potential, kinetic and total energies respectively double kB; // Boltzmann constant @@ -904,7 +904,8 @@ typedef struct _SPARC_OBJ{ double external_stress_cartesian[9]; //external_stress matrix multiply reciprocal_metric_tensor double constraint_stress[9]; // Stress generated by constraining the evolution of cell lattice vectors lengths or angles double kinetic_stress[9]; - double kinetic_stress1[9]; + double internal_stress_fractional[9]; // internal electronic stress (total stress minus ion-kinetic stress) in fractional coordinates + double total_internal_stress[9]; double Kbaro; // kinetic energy of barostat variables double Ubaro; // potential energy of barostat variables double SNOSE[3]; // Thermostat control related information: Position variable of thermostat, velocity of thermostat, position variable at previous time step @@ -914,7 +915,6 @@ typedef struct _SPARC_OBJ{ double Hamiltonian_NPH; // Hamiltonian of NPH system double init_Hamil_NPT_NP; // initial Hamiltonian in NPT_NP ensemble double init_Hamil_NPH; // initial Hamiltonian in NPH ensemble - double Snew; double mean_internal_pressure; double KE_save; //NPT_NP_specific diff --git a/src/include/md.h b/src/include/md.h index 21405dfd..8fe8a92f 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -156,15 +156,14 @@ void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC); @ brief: Performs Molecular Dynamics using NPT_NP. */ -void NPT_NP(SPARC_OBJ *pSPARC); +void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis); -void NPH(SPARC_OBJ *pSPARC); - -void NPT_NPH_main(SPARC_OBJ *pSPARC); +void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis); /* @ brief: Calculates cell angles, reciprocal lattice vectors, metric and reciprocal metric tensors, for use in NPT_NP and NPH dynamics */ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell); +void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC); void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC); @@ -172,8 +171,7 @@ void transpose_and_add(double *matrix1); void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC); -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional, double *ion_vel_fractional); -void Calculate_Kinetic_stress_and_total_internal_pressure1(SPARC_OBJ *pSPARC, double *internal_stress_fractional); +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC); void compute_constraint_stress(SPARC_OBJ *pSPARC); diff --git a/src/md.c b/src/md.c index 96cce019..5f58bc37 100644 --- a/src/md.c +++ b/src/md.c @@ -148,7 +148,7 @@ void main_MD(SPARC_OBJ *pSPARC) { else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) NPT_NH(pSPARC); else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPT_NP_and_NPH(pSPARC); + NPT_NP_and_NPH(pSPARC, output_md, avgvel, maxvel, mindis); //The last four arguments: output_md, avgvel, maxvel and mindis are only passed so as to facilitate calling 'MD_QOI' or 'Print_fullMD' function from within NPT_NP or NPH subroutines else{ if (!rank){ printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); @@ -156,11 +156,15 @@ void main_MD(SPARC_OBJ *pSPARC) { exit(EXIT_FAILURE); } - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + } if(check1) { fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written PrintMD(pSPARC, 1, print_restart_typ); @@ -197,8 +201,12 @@ void main_MD(SPARC_OBJ *pSPARC) { free(mindis); if (rank == 0 && pSPARC->fp_energy != NULL) { fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers + pSPARC->fp_energy = NULL; } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ + free(pSPARC->ion_vel_fractional); + free(pSPARC->Pm_ion); + } } /** @@ -299,7 +307,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->thermos_T = pSPARC->thermos_Ti; pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); @@ -358,11 +366,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { } pSPARC->KE_save = 0.0; fetch_MD_cell_ingredients(pSPARC, false); - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - exit(EXIT_FAILURE); - } + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ @@ -392,13 +396,23 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { } } - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) pSPARC->thermos_Ti = pSPARC->ion_T; pSPARC->thermos_T = pSPARC->thermos_Ti; + + pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); + exit(EXIT_FAILURE); + } + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); + exit(EXIT_FAILURE); + } } else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart int rank; @@ -418,12 +432,8 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->KE_save = 0.0; fetch_MD_cell_ingredients_restart(pSPARC); - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - exit(EXIT_FAILURE); - } - + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -448,6 +458,17 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! Calculate_ionic_stress(pSPARC); + + pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); + exit(EXIT_FAILURE); + } + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); + exit(EXIT_FAILURE); + } } if(pSPARC->RestartFlag == 0){ @@ -1405,7 +1426,7 @@ The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. Additional Reference for NPH: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." Physical Review B 55.14 (1997): 8733. */ -void NPT_NP_and_NPH(SPARC_OBJ *pSPARC) { +void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); @@ -1416,7 +1437,7 @@ void NPT_NP_and_NPH(SPARC_OBJ *pSPARC) { NPT_NP_and_NPH_init_hamiltonian(pSPARC); } //NPT_NPH_main routine - NPT_NPH_main(pSPARC); + NPT_NPH_main(pSPARC, output_md, avgvel, maxvel, mindis); // Reinitialize mesh size and related variables after changing size of cell reinitialize_mesh_NPT(pSPARC); // Charge extrapolation (for better rho_guess) @@ -1757,10 +1778,10 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dscal(9, pSPARC->SNOSE[0] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); } else { - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dscal(9, pSPARC->SNOSE[0] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); @@ -1803,12 +1824,10 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ } pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); - pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); - } -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *ion_vel_fractional){ +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -1819,12 +1838,12 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, dou int count = 0; for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+2] * pSPARC->ion_vel_fractional[count*3+2]; count++; } } @@ -1857,38 +1876,18 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // Calculating kinetic energy of ions + // Calculating kinetic energy of ions cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); - - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ion_vel_fractional array in the NPT_NP_and_NPH_init_hamiltonian function.\n"); - exit(EXIT_FAILURE); - } - + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->metric_tensor, 3, 0.0, pSPARC->Pm_ion, 3); int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, pSPARC->Mass[ityp], pSPARC->metric_tensor, 3, &ion_vel_fractional[count * 3], 1, 0.0, &pSPARC->Pm_ion[count * 3], 1); - count++; - } + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + cblas_dscal(3 * pSPARC->nAtomv[ityp], pSPARC->Mass[ityp], &pSPARC->Pm_ion[count], 1); + count = count + 3 * pSPARC->nAtomv[ityp]; } - // Calculate kinetic energy and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, ion_vel_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - - free(ion_vel_fractional); + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper pSPARC->KE_save = pSPARC->KE; @@ -1947,7 +1946,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ -update momentum */ -void NPT_NPH_main(SPARC_OBJ *pSPARC) { +void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); double ktemp = pSPARC->kB * pSPARC->thermos_T; @@ -1955,7 +1954,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { //Initialize empty temporary matrices and vectors double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; + double internal_stress_cartesian[9]; //Initialize some useful constants double baro_const1; @@ -1994,20 +1993,14 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { } - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds Eqn. 18h in the Hernandez paper internal_stress_cartesian[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3] - pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5] - pSPARC->stress_i[5]; internal_stress_cartesian[1] = pSPARC->stress[1] - pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1] - pSPARC->stress_i[1]; internal_stress_cartesian[5] = pSPARC->stress[4] - pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4] - pSPARC->stress_i[4]; - - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) - for (int i = 0; i < 9; i++){ - temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b, 3); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat_b, 3); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, pSPARC->reciprocal_lattice, 3, temp_mat_b, 3, 0.0, pSPARC->internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); @@ -2018,12 +2011,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { // Eqn. 18h Hernandez paper for (int i = 0; i < 9; i++){ - temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); + temp_mat[i] = (pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } - + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ if (pSPARC->NPT_NP_ANGLES == 0){ compute_constraint_stress(pSPARC); @@ -2037,7 +2030,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] = pSPARC->internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } @@ -2083,60 +2076,44 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds to Eqn. 18i in Hernandez paper - //cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - - double *D2C = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - D2C[count*3] = cblas_ddot(3, &pSPARC->full_lattice[0], 1, &pSPARC->forces[count*3], 1); - D2C[count*3 + 1] = cblas_ddot(3, &pSPARC->full_lattice[3], 1, &pSPARC->forces[count*3], 1); - D2C[count*3 + 2] = cblas_ddot(3, &pSPARC->full_lattice[6], 1, &pSPARC->forces[count*3], 1); - count++; - } + double *ion_forces_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); + exit(EXIT_FAILURE); } - + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->forces, 3, pSPARC->full_lattice, 3, 0.0, ion_forces_fractional, 3); // Eqn. 18i: momentum += 0.5 * dt * S * D2C - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], D2C, 1, pSPARC->Pm_ion, 1); + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], pSPARC->ion_forces_fractional, 1, pSPARC->Pm_ion, 1); //Update the kinetic energy of the Ionic particles Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - double *D2 = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); - + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); count = 0; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - D2[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - D2[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - D2[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - count++; - } + cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); + count = count + 3 * pSPARC->nAtomv[ityp]; } - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, D2); - free(D2); - - double total_internal_stress[9]; + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - pSPARC->internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); } - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); //Update Hamiltonian double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; - } + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; + // } pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper } else { - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPH = sumAllHamilTerms ; - } + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; + // } pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } #ifdef DEBUG @@ -2153,44 +2130,28 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); - } } else { printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPH, - pSPARC->SNOSE[0], // snose(1) in Fortran is s - pSPARC->init_Hamil_NPH, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure);; - } } - } #endif - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + // For printing, convert the total internal stress and the kinetic stress to cartesian coordinates + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->total_internal_stress, 3); //Mutliplied by 2 so as to remove the effect of previous divisions by 2 in the kinetic_stress, internal_stress_fractional + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, -2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress + + // Obtain updated velocities in cartesian coordinates for use in MD_QOI function + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + int check1 = (pSPARC->PrintMDout == 1 && !rank); + MD_QOI(avgvel, maxvel, mindis); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) @@ -2198,33 +2159,25 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { // Now we update/Step-up the momenta of the Ionic particles by dt/2 // This setup corresponds to Eqn. 18a in Hernandez paper - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], D2C, 1, pSPARC->Pm_ion, 1); - free(D2C); - + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); + free(ion_forces_fractional); //Update the kinetic energy of the Ionic particles Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - double *ion_vel_fractional = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); - + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); count = 0; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - ion_vel_fractional[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - ion_vel_fractional[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - ion_vel_fractional[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - count++; - } + cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); + count = count + 3 * pSPARC->nAtomv[ityp]; } - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, ion_vel_fractional); + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); // Now we update/Step-up the momenta of the barostat by dt/2 // This setup corresponds to Eqn. 18b in the Hernandez paper // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); + Update_metric_tensor_momenta_iteratively_half_step(pSPARC); //Now impose the constraints on it if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ @@ -2313,78 +2266,48 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); + //Eqn. 18e is implicitly solved in the below subroutine + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); - //Before updating cell parameters, compute atom positions in fractional coordinates + //Before updating cell parameters, convert cartesian atomic position coordinates to fractional double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - //double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); - count++; - } - pSPARC->Snew = S_temp; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, pSPARC->reciprocal_lattice, 3, 0.0, atom_pos_fractional, 3); + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor fetch_MD_cell_ingredients(pSPARC, true); - //Update the Potential energy of the barostat based on new metric tensor + //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - //Update the Kinetic energy of the barostat based on new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic - - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = atom_pos_fractional[count * 3] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3] / S_temp ); // - atom_pos_fractional[count * 3 + 1] = atom_pos_fractional[count * 3 + 1] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3 + 1] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3 + 1] / S_temp ); // - atom_pos_fractional[count * 3 + 2] = atom_pos_fractional[count * 3 + 2] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3 + 2] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3 + 2] / S_temp ); // - count++; - } - + //Update Atomic position in fractional coordinates (Eqn. 18f in Hernandez paper) + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel_fractional, 1, atom_pos_fractional, 1); // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); - count++; - } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, atom_pos_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->atom_pos, 3); free(atom_pos_fractional); - free(ion_vel_fractional); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + //Update atomic positions and restore ionic velocities - count = 0; - for(int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] /= S_temp; - pSPARC->ion_vel[count * 3 + 1] /= S_temp; - pSPARC->ion_vel[count * 3 + 2] /= S_temp; - count ++; - } + cblas_dscal(3 * pSPARC->n_atom, 1 / S_new, pSPARC->ion_vel, 1); //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); + pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); pSPARC->KE_save = pSPARC->KE; - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); + pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); } // Update SNOSE[0] to S_new if (pSPARC->NPT_NP_qmass > 0){ pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_temp; + pSPARC->SNOSE[0] = S_new; } // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// @@ -2656,7 +2579,7 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants @@ -2699,7 +2622,7 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, doubl // Eqn. 18b Hernandez paper for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] = pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } @@ -2949,15 +2872,21 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha \n"); + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha \n"); } if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell expansion). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated as: kinetic_stress (positive convention) - electronic stress - constraint stress; as per (E. Hernandez, 2001) paper + } } if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_TOTSTRESS: Total internal pressure (also accounting pressure due to any constraint on cell expansion). Unit=GPa \n"); + } fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" " where N = number of particles, k = Boltzmann constant, V = volume\n"); } @@ -3031,7 +2960,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); } else { fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x / pSPARC->initialLatVecLength[0], pSPARC->range_y / pSPARC->initialLatVecLength[1], pSPARC->range_z / pSPARC->initialLatVecLength[2]); fprintf(output_md,":LatVec:\n"); fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] @@ -3041,15 +2970,33 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // Print stress if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + else{ //Trigger NPT_NP or NPH ensemble stress printing + fprintf(output_md,":STRIO:\n"); + double temp_stress[6]; + temp_stress[0] = pSPARC->kinetic_stress[0]; temp_stress[1] = pSPARC->kinetic_stress[1]; temp_stress[2] = pSPARC->kinetic_stress[2]; + temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[7]; + PrintStress (pSPARC, temp_stress, output_md); //Print kinetic stress as defined in the (E. Hernandez, 2001) paper + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + fprintf(output_md,":TOTSTRESS:\n"); //Print total internal stress accouting for the constraints in NPT_NP or NPH ensemble + temp_stress[0] = pSPARC->total_internal_stress[0]; temp_stress[1] = pSPARC->total_internal_stress[1]; temp_stress[2] = pSPARC->total_internal_stress[2]; + temp_stress[3] = pSPARC->total_internal_stress[4]; temp_stress[4] = pSPARC->total_internal_stress[5]; temp_stress[5] = pSPARC->total_internal_stress[7]; + PrintStress (pSPARC, temp_stress, output_md); + } + } // print pressure if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { // find pressure of ideal gas: NkT/V @@ -3064,9 +3011,19 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma double pres_ig = 0.0; pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i * CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i) * CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig * CONST_HA_BOHR3_GPA); // Ideal Gas + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i) * CONST_HA_BOHR3_GPA); + } + else{ //Trigger NPT_NP or NPH ensemble stress printing + double ion_kinetic_pressure; + ion_kinetic_pressure = -1.0 / 3.0 * (pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[1] + pSPARC->kinetic_stress[2]); //Kinetic stress is already multiplied by 2 + fprintf(output_md,":PRESIO: %18.10E\n", ion_kinetic_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->internal_pressure - ion_kinetic_pressure) * CONST_HA_BOHR3_GPA); + fprintf(output_md,":TOTPRES: %18.10E\n", pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); //Also accounts for pressure due to constraint stress + } + + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig * CONST_HA_BOHR3_GPA); // Ideal Gas } @@ -3120,19 +3077,19 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); } pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - - pSPARC->TE = (pSPARC->PE + pSPARC->KE/pSPARC->n_atom); + pSPARC->KE = pSPARC->KE / pSPARC->n_atom + pSPARC->TE = (pSPARC->PE + pSPARC->KE); // Extended System (Ionic system + Thermostat) energy if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; } // Compute Ionic stress/pressure - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - - if ((pSPARC->MDCount == 0) && (pSPARC->RestartFlag != 1)) { - pSPARC->mean_internal_pressure = (pSPARC->pres-pSPARC->pres_i); + + if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); } + // Calculate_stress(pSPARC); #ifdef DEBUG // MD Statistics @@ -3386,48 +3343,21 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); } - // Print extended system parameters in case of NPT-NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":NPT_NP_SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep - fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] - , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] - , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] - , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] - , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); + // Print extended system parameters in case of NPT-NP or NPH ensemble + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":NPT_NP_SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep + fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep + fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); } - fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); - fprintf(mdout,":ROTATION_MATRIX: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] - , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] - , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * 29421.02648438959); - fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * 29421.02648438959 - ,pSPARC->stress_external[1] * 29421.02648438959 - ,pSPARC->stress_external[2] * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - // Print extended system parameters in case of NPH - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - // fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - // , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - // , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":LATTICE_AVG_VELOCITY: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice if (pSPARC->Flag_latvec_scale == 0){ @@ -3452,8 +3382,7 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { ,pSPARC->stress_external[2] * 29421.02648438959 ,pSPARC->stress_external[3] * 29421.02648438959 ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + ,pSPARC->stress_external[5] * 29421.02648438959); } // Print temperature fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); @@ -3609,80 +3538,40 @@ void RestartMD(SPARC_OBJ *pSPARC) { else if (strcmpi(str,":TARGET_PRESSURE:") == 0) fscanf(rst_fp,"%lf", &pSPARC->prtarget); } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[0]); - else if (strcmpi(str,":NPT_NP_SNOSE[1]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[1]); - else if (strcmpi(str,":NPT_NP_SNOSE[2]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[2]); - else if (strcmpi(str,":LATTICE_AVG_VELOCITY:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[0]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[1]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[2]); - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[3]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[4]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[5]); - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[6]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[7]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[8]); - } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); - } else if (strcmpi(str,":CELL:") == 0) { - fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); - - } else if (strcmpi(str,":LatUVec:") == 0) { - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); - - } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->range_x = pSPARC->initialLatVecLength[0]*pSPARC->latvec_scale_x; - pSPARC->range_y = pSPARC->initialLatVecLength[1]*pSPARC->latvec_scale_y; - pSPARC->range_z = pSPARC->initialLatVecLength[2]*pSPARC->latvec_scale_z; - - } else if (strcmpi(str,":LatVec:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); - fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); - fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); - - } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[6]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[7]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[8]); + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[0]); + else if (strcmpi(str,":NPT_NP_SNOSE[1]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[1]); + else if (strcmpi(str,":NPT_NP_SNOSE[2]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[2]); + else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":EXTERNAL_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->pressure_external); - else if (strcmpi(str,":EXTERNAL_STRESS:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->stress_external[0]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[1]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[2]); - fscanf(rst_fp,"%lf", &pSPARC->stress_external[3]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[4]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[5]); + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (strcmpi(str,":NPH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPH_bmass); + else if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); } - else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - if (strcmpi(pSPARC->MDMeth,"NPH") == 0) { - if (strcmpi(str,":NPH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPH_bmass); else if (strcmpi(str,":LATTICE_AVG_VELOCITY:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[0]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[1]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[2]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[3]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[4]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[5]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[6]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[7]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[8]); + } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); } else if (strcmpi(str,":CELL:") == 0) { fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); - } else if (strcmpi(str,":LatUVec:") == 0) { fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); - } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); fscanf(rst_fp, "%*[^\n]\n"); @@ -3693,18 +3582,15 @@ void RestartMD(SPARC_OBJ *pSPARC) { pSPARC->range_x = pSPARC->initialLatVecLength[0]*pSPARC->latvec_scale_x; pSPARC->range_y = pSPARC->initialLatVecLength[1]*pSPARC->latvec_scale_y; pSPARC->range_z = pSPARC->initialLatVecLength[2]*pSPARC->latvec_scale_z; - } else if (strcmpi(str,":LatVec:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); - } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[6]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[7]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[8]); - } - else if (strcmpi(str,":TTHRMI(K):") == 0) + } else if (strcmpi(str,":TTHRMI(K):") == 0) fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); else if (strcmpi(str,":EXTERNAL_PRESSURE:") == 0) fscanf(rst_fp,"%lf", &pSPARC->pressure_external); @@ -3712,8 +3598,6 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->stress_external[0]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[1]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[2]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[3]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[4]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[5]); } - else if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); } } fclose(rst_fp); @@ -3748,6 +3632,18 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Pack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } MPI_Pack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); @@ -3763,18 +3659,6 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Pack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } } } @@ -3820,6 +3704,18 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); } else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[0], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[1], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[2], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPH_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); @@ -3835,18 +3731,6 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->pressure_external, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->stress_external, 6, MPI_DOUBLE, MPI_COMM_WORLD); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[0], 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[1], 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[2], 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPH_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } } } @@ -3861,7 +3745,6 @@ void RestartMD(SPARC_OBJ *pSPARC) { } - /* @ brief: function to rename the restart file */ From e067d350be195328989cc61d414793ccfd4c31c5 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 31 Mar 2026 19:59:22 -0400 Subject: [PATCH 34/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 2 +- src/include/md.h | 2 +- src/md.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index 598814dc..763a0109 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -820,7 +820,7 @@ typedef struct _SPARC_OBJ{ double *ion_vel; // Ionic velocity double *ion_accel; // Ionic acceleration double *Pm_ion; // Ionic momenta - double *ion_vel_fractional // Ionic velocity in fractional coordinates + double *ion_vel_fractional; // Ionic velocity in fractional coordinates double ion_T; // Ionic temperature double PE, KE, TE, TE_ext; // potential, kinetic and total energies respectively double kB; // Boltzmann constant diff --git a/src/include/md.h b/src/include/md.h index 8fe8a92f..93cff995 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -177,7 +177,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC); void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new); -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional); +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC); /** * @ brief: function to convert non cartesian to cartesian coordinates and velocities, from initialization.c */ diff --git a/src/md.c b/src/md.c index 5f58bc37..8351deb1 100644 --- a/src/md.c +++ b/src/md.c @@ -2083,7 +2083,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->forces, 3, pSPARC->full_lattice, 3, 0.0, ion_forces_fractional, 3); // Eqn. 18i: momentum += 0.5 * dt * S * D2C - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], pSPARC->ion_forces_fractional, 1, pSPARC->Pm_ion, 1); + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); //Update the kinetic energy of the Ionic particles Calculate_Ionic_particles_Kinetic_energy(pSPARC); @@ -2147,7 +2147,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // Obtain updated velocities in cartesian coordinates for use in MD_QOI function cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); int check1 = (pSPARC->PrintMDout == 1 && !rank); - MD_QOI(avgvel, maxvel, mindis); + MD_QOI(pSPARC, avgvel, maxvel, mindis); Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// @@ -3077,7 +3077,7 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); } pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE / pSPARC->n_atom + pSPARC->KE = pSPARC->KE / pSPARC->n_atom; pSPARC->TE = (pSPARC->PE + pSPARC->KE); // Extended System (Ionic system + Thermostat) energy if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ From 762ee1f694e69caa1774e7d33e3d30cdf4c33ef1 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 31 Mar 2026 21:51:04 -0400 Subject: [PATCH 35/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/MD_printing_refined_fractional.c | 3755 ++++++++++++++++++++++++++ src/md.c | 17 +- 2 files changed, 3763 insertions(+), 9 deletions(-) create mode 100644 src/MD_printing_refined_fractional.c diff --git a/src/MD_printing_refined_fractional.c b/src/MD_printing_refined_fractional.c new file mode 100644 index 00000000..85150bea --- /dev/null +++ b/src/MD_printing_refined_fractional.c @@ -0,0 +1,3755 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include +#include +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + pSPARC->internal_pressure = 0; + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPT_NP_and_NPH(pSPARC, output_md, avgvel, maxvel, mindis); //The last four arguments: output_md, avgvel, maxvel and mindis are only passed so as to facilitate calling 'MD_QOI' or 'Print_fullMD' function from within NPT_NP or NPH subroutines + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + } + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ + free(pSPARC->ion_vel_fractional); + free(pSPARC->Pm_ion); + } +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + if (pSPARC->Flag_latvec_scale == 1){ + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else{ + pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; + } + + pSPARC->maxTimeIter = 100; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); + printf("herere"); + exit(EXIT_FAILURE); + } + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + if(pSPARC->NPH_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); + printf("he1"); + exit(EXIT_FAILURE); + } + } + } + + if (rank == 0) { + // "w" creates a new file; "a" appends to an existing one. + pSPARC->fp_energy = fopen("MD_energies_NPH2.log", "w"); + + if (pSPARC->fp_energy == NULL) { + fprintf(stderr, "Error: Could not open energy log file!\n"); + exit(EXIT_FAILURE); + } + + // Optional: Print a header to make the file readable in Excel/Python + fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", + "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); + fflush(pSPARC->fp_energy); + } + pSPARC->KE_save = 0.0; + fetch_MD_cell_ingredients(pSPARC, false); + + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble\n"); + } + } + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); + exit(EXIT_FAILURE); + } + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); + exit(EXIT_FAILURE); + } + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; //This is computed in function: 'fetch_MD_cell_ingredients_restart' below + + if (pSPARC->Flag_latvec_scale == 1){ + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else{ + pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; + } + pSPARC->maxTimeIter = 100; + + pSPARC->KE_save = 0.0; + fetch_MD_cell_ingredients_restart(pSPARC); + + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; + pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; + pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; + pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPH")){ + pSPARC->NPT_NP_qmass = 0; + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + } + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + + Calculate_ionic_stress(pSPARC); + + pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); + exit(EXIT_FAILURE); + } + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); + exit(EXIT_FAILURE); + } + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant. +Also performs NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant. NPH in this scheme is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference for NPT_NP and NPH: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Additional Reference for NPH: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine + NPT_NPH_main(pSPARC, output_md, avgvel, maxvel, mindis); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + +void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + int i, j, k; + + double TEMP_TOL = 1e-12; + // Construct LatUVec; + double mag; + for(i = 0; i < 3; i++){ + mag = sqrt(pow(pSPARC->full_lattice[3 * i], 2.0) + + pow(pSPARC->full_lattice[3 * i + 1], 2.0) + + pow(pSPARC->full_lattice[3 * i + 2], 2.0)); + pSPARC->LatUVec[3 * i] = pSPARC->full_lattice[3 * i]/mag; + pSPARC->LatUVec[3 * i + 1] = pSPARC->full_lattice[3 * i + 1]/mag; + pSPARC->LatUVec[3 * i + 2] = pSPARC->full_lattice[3 * i + 2]/mag; + } + + // determinant of 3x3 Jacobian + pSPARC->Jacbdet = 0.0; + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + if(i != j && j != k && k != i) + pSPARC->Jacbdet += ((i - j) * (j - k) * (k - i)/2) * pSPARC->LatUVec[3 * i] * pSPARC->LatUVec[3 * j + 1] * pSPARC->LatUVec[3 * k + 2]; + } + } + } + + if(pSPARC->Jacbdet <= 0){ + if(rank == 0) + printf("ERROR: Volume(det(jacobian)) %lf is <= 0\n", pSPARC->Jacbdet); + exit(EXIT_FAILURE); + } + + // transformation matrix for distance + for(i = 0; i < 9; i++) + pSPARC->metricT[i] = 0.0; + + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + pSPARC->metricT[3*i + j] += pSPARC->LatUVec[3*i + k] * pSPARC->LatUVec[3*j + k]; + } + } + } + + pSPARC->metricT[1] = 2 * pSPARC->metricT[1]; + pSPARC->metricT[2] = 2 * pSPARC->metricT[2]; + pSPARC->metricT[5] = 2 * pSPARC->metricT[5]; + + // transformation matrix for gradient + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + pSPARC->gradT[3*j + i] = (pSPARC->LatUVec[3 * ((j+1) % 3) + (i+1) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+2) % 3] - pSPARC->LatUVec[3 * ((j+1) % 3) + (i+2) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+1) % 3])/pSPARC->Jacbdet; + } + } + + // transformation matrix for laplacian + for(i = 0; i < 9; i++) + pSPARC->lapcT[i] = 0.0; + + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + pSPARC->lapcT[3*i + j] += pSPARC->gradT[3*i + k] * pSPARC->gradT[3*j + k]; + } + } + } + + /* Different cell types for laplacian */ + if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 11; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 12; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 13; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 14; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 15; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 16; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 17; +#ifdef DEBUG + if(!rank) + printf("\n\nCELL_TYP: %d\n\n",pSPARC->cell_typ); +#endif + /* transform the coefficiens of lapacian*/ + // int p, FDn = pSPARC->order/2; + // double dx_inv, dy_inv, dz_inv, dx2_inv, dy2_inv, dz2_inv; + // dx_inv = 1.0 / (pSPARC->delta_x); + // dy_inv = 1.0 / (pSPARC->delta_y); + // dz_inv = 1.0 / (pSPARC->delta_z); + // dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + // dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + // dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + // for (p = 0; p < FDn + 1; p++) { + // pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + // pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + // pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + // pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + // pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + // pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + // pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + // pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + // pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + // pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + // pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + // pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + // } + // TODO: Find maximum eigenvalue of Hamiltionian (= max. eigvalue of -0.5 lap) for non orthogonal periodic systems +} + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ + +void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat_MD(pSPARC); + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + +} + +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Cosine of Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; + + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat_MD(pSPARC); + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + + } + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell@Rotation_matrix.T = old_cell; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate the velocity of cell lattice vectors (only useful in 1st MD step (start afresh or restart)) + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->SNOSE[0] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->SNOSE[0] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } + + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double vector[3]={0.0}; + pSPARC->KE = 0.0; + + int count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, &pSPARC->Pm_ion[count*3], 1, 0.0, vector, 1); + pSPARC->KE += cblas_ddot(3, vector, 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + count++; + } + } + + pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+2] * pSPARC->ion_vel_fractional[count*3+2]; + count++; + } + } + + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else { + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + double ktemp = pSPARC->kB * pSPARC->thermos_T; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + + // Calculating kinetic energy of ions + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->metric_tensor, 3, 0.0, pSPARC->Pm_ion, 3); + int count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + cblas_dscal(3 * pSPARC->nAtomv[ityp], pSPARC->Mass[ityp], &pSPARC->Pm_ion[count], 1); + count = count + 3 * pSPARC->nAtomv[ityp]; + } + // Calculate kinetic energy and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + pSPARC->KE_save = pSPARC->KE; + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + + double sumAllHamilTerms; + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// + + //Initialize constraint stress to 0 + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; + } +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp = pSPARC->kB * pSPARC->thermos_T; + int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const3 = 1.0 / baro_const1; + + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// + + //Calculate_Ionic_particles_Kinetic_energy(pSPARC); + pSPARC->KE = pSPARC->KE_save; + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double Sa = 0.0; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; + pSPARC->SNOSE[1] += 0.5 * Sa * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; + #ifdef DEBUG + if (rank == 0) { + printf("Sa is %12.9f\n", Sa); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + } + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3] - pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5] - pSPARC->stress_i[5]; + internal_stress_cartesian[1] = pSPARC->stress[1] - pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1] - pSPARC->stress_i[1]; + internal_stress_cartesian[5] = pSPARC->stress[4] - pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4] - pSPARC->stress_i[4]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat_b, 3); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, pSPARC->reciprocal_lattice, 3, temp_mat_b, 3, 0.0, pSPARC->internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = (pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC); + } + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = pSPARC->internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + double *ion_forces_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); + exit(EXIT_FAILURE); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->forces, 3, pSPARC->full_lattice, 3, 0.0, ion_forces_fractional, 3); + // Eqn. 18i: momentum += 0.5 * dt * S * D2C + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); + count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); + count = count + 3 * pSPARC->nAtomv[ityp]; + } + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + + for (int i = 0; i < 9; i++){ + pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - pSPARC->internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); + + //Update Hamiltonian + double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; + // } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; + // } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } + } + #endif + + // For printing, convert the total internal stress and the kinetic stress to cartesian coordinates + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->total_internal_stress, 3); //Mutliplied by 2 so as to remove the effect of previous divisions by 2 in the kinetic_stress, internal_stress_fractional + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, -2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress + + // Obtain updated velocities in cartesian coordinates for use in MD_QOI function + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + int check1 = (pSPARC->PrintMDout == 1 && !rank); + MD_QOI(pSPARC, avgvel, maxvel, mindis); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); + free(ion_forces_fractional); + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); + count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); + count = count + 3 * pSPARC->nAtomv[ityp]; + } + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC); + + //Now impose the constraints on it + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + else { + if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + } + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + } + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp - S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + printf("%15.7f \n", S_new); + printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + + //Eqn. 18e is implicitly solved in the below subroutine + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); + + //Before updating cell parameters, convert cartesian atomic position coordinates to fractional + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, pSPARC->reciprocal_lattice, 3, 0.0, atom_pos_fractional, 3); + + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + + //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + //Update Atomic position in fractional coordinates (Eqn. 18f in Hernandez paper) + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel_fractional, 1, atom_pos_fractional, 1); + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, atom_pos_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->atom_pos, 3); + free(atom_pos_fractional); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + + //Update atomic positions and restore ionic velocities + cblas_dscal(3 * pSPARC->n_atom, 1 / S_new, pSPARC->ion_vel, 1); + + //Update kinetic energy and kinetic stress based on new S + pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); + pSPARC->KE_save = pSPARC->KE; + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); + } + + // Update SNOSE[0] to S_new + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_new; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// +} + + +void compute_constraint_stress(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + else { + if (pSPARC->NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); + } + + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + if (pSPARC->NPTconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPTconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + else { + if (pSPARC->NPH_ANGLES == 0){ + if (pSPARC->NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (pSPARC->NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0]); + b_norm = sqrt( new_metric_tensor[4]); + c_norm = sqrt( new_metric_tensor[8]); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + } + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } + } + #endif + +} + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-12; // tolerance criterion for checking convergence + double baro_const0, baro_const3, baro_const5; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + + } + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif + } +} + + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); + else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell expansion). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated as: kinetic_stress (positive convention) - electronic stress - constraint stress; as per (E. Hernandez, 2001) paper + } + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_TOTSTRESS: Total internal pressure (also accounting pressure due to any constraint on cell expansion). Unit=GPa \n"); + } + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); + if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x / pSPARC->initialLatVecLength[0], pSPARC->range_y / pSPARC->initialLatVecLength[1], pSPARC->range_z / pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + else{ //Trigger NPT_NP or NPH ensemble stress printing + fprintf(output_md,":STRIO:\n"); + double temp_stress[6]; + temp_stress[0] = pSPARC->kinetic_stress[0]; temp_stress[1] = pSPARC->kinetic_stress[1]; temp_stress[2] = pSPARC->kinetic_stress[2]; + temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[7]; + PrintStress (pSPARC, temp_stress, output_md); //Print kinetic stress as defined in the (E. Hernandez, 2001) paper + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + fprintf(output_md,":TOTSTRESS:\n"); //Print total internal stress accouting for the constraints in NPT_NP or NPH ensemble + temp_stress[0] = pSPARC->total_internal_stress[0]; temp_stress[1] = pSPARC->total_internal_stress[1]; temp_stress[2] = pSPARC->total_internal_stress[2]; + temp_stress[3] = pSPARC->total_internal_stress[4]; temp_stress[4] = pSPARC->total_internal_stress[5]; temp_stress[5] = pSPARC->total_internal_stress[7]; + PrintStress (pSPARC, temp_stress, output_md); + } + } + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i) * CONST_HA_BOHR3_GPA); + } + else{ //Trigger NPT_NP or NPH ensemble stress printing + double ion_kinetic_pressure; + ion_kinetic_pressure = -1.0 / 3.0 * (pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[1] + pSPARC->kinetic_stress[2]); //Kinetic stress is already multiplied by 2 + fprintf(output_md,":PRESIO: %18.10E\n", ion_kinetic_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->internal_pressure - ion_kinetic_pressure) * CONST_HA_BOHR3_GPA); + fprintf(output_md,":TOTPRES: %18.10E\n", pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); //Also accounts for pressure due to constraint stress + } + + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig * CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":PREST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the quantities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE / pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + // Compute Ionic stress/pressure + + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old; + int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + mean_internal_pressure_old = pSPARC->mean_internal_pressure; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_internal_pressure = sqrt(fabs( ((pow(pSPARC->std_internal_pressure,2.0) + pow(mean_internal_pressure_old,2.0)) * (Count - 1) + pow(pSPARC->internal_pressure,2.0))/Count - pow(pSPARC->mean_internal_pressure,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(9, sizeof(double)); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + printf("\n"); + printf("\n"); + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP or NPH ensemble + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":NPT_NP_SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep + fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep + fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] + , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] + , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] + , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] + , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); + } + fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); + fprintf(mdout,":ROTATION_MATRIX: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] + , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] + , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * 29421.02648438959); + fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * 29421.02648438959 + ,pSPARC->stress_external[1] * 29421.02648438959 + ,pSPARC->stress_external[2] * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + } + // Print temperature + fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); + + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[0]); + else if (strcmpi(str,":NPT_NP_SNOSE[1]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[1]); + else if (strcmpi(str,":NPT_NP_SNOSE[2]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[2]); + else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (strcmpi(str,":NPH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPH_bmass); + else if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); + } + else if (strcmpi(str,":LATTICE_AVG_VELOCITY:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[0]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[1]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[2]); + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[3]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[4]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[5]); + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[6]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[7]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[8]); + + } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); + } else if (strcmpi(str,":CELL:") == 0) { + fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); + } else if (strcmpi(str,":LatUVec:") == 0) { + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); + } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->range_x = pSPARC->initialLatVecLength[0]*pSPARC->latvec_scale_x; + pSPARC->range_y = pSPARC->initialLatVecLength[1]*pSPARC->latvec_scale_y; + pSPARC->range_z = pSPARC->initialLatVecLength[2]*pSPARC->latvec_scale_z; + } else if (strcmpi(str,":LatVec:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); + fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); + fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); + } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[6]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[7]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[8]); + } else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":EXTERNAL_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->pressure_external); + else if (strcmpi(str,":EXTERNAL_STRESS:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->stress_external[0]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[1]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[2]); + fscanf(rst_fp,"%lf", &pSPARC->stress_external[3]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[4]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[5]); + } + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Pack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + MPI_Pack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if (pSPARC->Flag_latvec_scale == 0){ + MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if (pSPARC->Flag_latvec_scale == 1){ + MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[0], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[1], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[2], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPH_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if (pSPARC->Flag_latvec_scale == 0){ + MPI_Unpack(buff, l_buff, &position, pSPARC->LatUVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if (pSPARC->Flag_latvec_scale == 1){ + MPI_Unpack(buff, l_buff, &position, pSPARC->LatVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); + } + MPI_Unpack(buff, l_buff, &position, pSPARC->rotation_matrix, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->pressure_external, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->stress_external, 6, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + + diff --git a/src/md.c b/src/md.c index 8351deb1..85150bea 100644 --- a/src/md.c +++ b/src/md.c @@ -580,8 +580,8 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { #ifdef DEBUG // Statistics to be set to zero initially pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; #endif } @@ -2908,7 +2908,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE/pSPARC->n_atom); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); @@ -3031,7 +3031,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // Print Statistical properties fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":PRES_INT: %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PREST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); @@ -3085,10 +3085,8 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { } // Compute Ionic stress/pressure - if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - } + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); // Calculate_stress(pSPARC); #ifdef DEBUG @@ -3103,9 +3101,9 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { mean_U_old = pSPARC->mean_U; mean_Eent_old = pSPARC->mean_Entropy; mean_internal_pressure_old = pSPARC->mean_internal_pressure; - pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; @@ -3113,6 +3111,7 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_internal_pressure = sqrt(fabs( ((pow(pSPARC->std_internal_pressure,2.0) + pow(mean_internal_pressure_old,2.0)) * (Count - 1) + pow(pSPARC->internal_pressure,2.0))/Count - pow(pSPARC->mean_internal_pressure,2.0) )); pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); From abd32d30cc8f182d32063f3d21ee4ed1b9dbd22b Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Tue, 31 Mar 2026 23:36:13 -0400 Subject: [PATCH 36/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/md.h | 2 + src/md.c | 522 ++++++++-------------------- src/md_working_Cartesian_velocity.c | 19 +- 3 files changed, 163 insertions(+), 380 deletions(-) diff --git a/src/include/md.h b/src/include/md.h index 93cff995..805d7a20 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -173,6 +173,8 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC); void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC); +Calculate_Kinetic_energy_and_Kinetic_stress(SPARC_OBJ *pSPARC); + void compute_constraint_stress(SPARC_OBJ *pSPARC); void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new); diff --git a/src/md.c b/src/md.c index 85150bea..6ded0617 100644 --- a/src/md.c +++ b/src/md.c @@ -1471,119 +1471,6 @@ void transpose_and_add(double *matrix1){ matrix1[5] = matrix1[7] = s12; } -void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - int i, j, k; - - double TEMP_TOL = 1e-12; - // Construct LatUVec; - double mag; - for(i = 0; i < 3; i++){ - mag = sqrt(pow(pSPARC->full_lattice[3 * i], 2.0) - + pow(pSPARC->full_lattice[3 * i + 1], 2.0) - + pow(pSPARC->full_lattice[3 * i + 2], 2.0)); - pSPARC->LatUVec[3 * i] = pSPARC->full_lattice[3 * i]/mag; - pSPARC->LatUVec[3 * i + 1] = pSPARC->full_lattice[3 * i + 1]/mag; - pSPARC->LatUVec[3 * i + 2] = pSPARC->full_lattice[3 * i + 2]/mag; - } - - // determinant of 3x3 Jacobian - pSPARC->Jacbdet = 0.0; - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - if(i != j && j != k && k != i) - pSPARC->Jacbdet += ((i - j) * (j - k) * (k - i)/2) * pSPARC->LatUVec[3 * i] * pSPARC->LatUVec[3 * j + 1] * pSPARC->LatUVec[3 * k + 2]; - } - } - } - - if(pSPARC->Jacbdet <= 0){ - if(rank == 0) - printf("ERROR: Volume(det(jacobian)) %lf is <= 0\n", pSPARC->Jacbdet); - exit(EXIT_FAILURE); - } - - // transformation matrix for distance - for(i = 0; i < 9; i++) - pSPARC->metricT[i] = 0.0; - - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - pSPARC->metricT[3*i + j] += pSPARC->LatUVec[3*i + k] * pSPARC->LatUVec[3*j + k]; - } - } - } - - pSPARC->metricT[1] = 2 * pSPARC->metricT[1]; - pSPARC->metricT[2] = 2 * pSPARC->metricT[2]; - pSPARC->metricT[5] = 2 * pSPARC->metricT[5]; - - // transformation matrix for gradient - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - pSPARC->gradT[3*j + i] = (pSPARC->LatUVec[3 * ((j+1) % 3) + (i+1) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+2) % 3] - pSPARC->LatUVec[3 * ((j+1) % 3) + (i+2) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+1) % 3])/pSPARC->Jacbdet; - } - } - - // transformation matrix for laplacian - for(i = 0; i < 9; i++) - pSPARC->lapcT[i] = 0.0; - - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - pSPARC->lapcT[3*i + j] += pSPARC->gradT[3*i + k] * pSPARC->gradT[3*j + k]; - } - } - } - - /* Different cell types for laplacian */ - if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 11; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 12; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 13; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 14; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 15; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 16; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 17; -#ifdef DEBUG - if(!rank) - printf("\n\nCELL_TYP: %d\n\n",pSPARC->cell_typ); -#endif - /* transform the coefficiens of lapacian*/ - // int p, FDn = pSPARC->order/2; - // double dx_inv, dy_inv, dz_inv, dx2_inv, dy2_inv, dz2_inv; - // dx_inv = 1.0 / (pSPARC->delta_x); - // dy_inv = 1.0 / (pSPARC->delta_y); - // dz_inv = 1.0 / (pSPARC->delta_z); - // dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - // dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - // dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - // for (p = 0; p < FDn + 1; p++) { - // pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - // pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - // pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - // pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - // pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - // pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - // pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - // pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - // pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - // pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - // pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - // pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - // } - // TODO: Find maximum eigenvalue of Hamiltionian (= max. eigvalue of -0.5 lap) for non orthogonal periodic systems -} /* Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix @@ -1608,8 +1495,15 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ //Compute metric_tensor (G) in real-space (not reciprocal space) cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + // This is needed since, they will be used in function 'Cart2nonCart_transformMat' to update various quantities + for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles + pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = ( pSPARC->LatUVec[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = ( pSPARC->LatUVec[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; + } + //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat_MD(pSPARC); + Cart2nonCart_transformMat(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) @@ -1703,8 +1597,20 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + //Update LATVEC_SCALE and LatVec + for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles + pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = ( pSPARC->LatUVec[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = ( pSPARC->LatUVec[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; + } + if (pSPARC->Flag_latvec_scale == 1){ // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + } + //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat_MD(pSPARC); + Cart2nonCart_transformMat(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) @@ -1716,22 +1622,6 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - } //Update reciprocal lattice vectors, reciprocal metric tensor for (int i = 0; i < 9; i++){ @@ -1816,9 +1706,8 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ int count = 0; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, &pSPARC->Pm_ion[count*3], 1, 0.0, vector, 1); - pSPARC->KE += cblas_ddot(3, vector, 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + pSPARC->KE += pSPARC->Mass[ityp] * ( pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count*3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count*3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count*3 + 2] ); count++; } } @@ -1827,7 +1716,7 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ } -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ +void Calculate_Kinetic_energy_and_Kinetic_stress(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -1838,21 +1727,26 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ int count = 0; for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+2] * pSPARC->ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+2] * pSPARC->ion_vel[count*3+2]; count++; } } - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); + + pSPARC->KE = pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[4] + pSPARC->kinetic_stress[8]; + + //Convert kinetic stress to fractional coordinates + double temp_mat1[9]; + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat1, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat1, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); } @@ -1877,19 +1771,10 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // Calculating kinetic energy of ions + // // Calculate kinetic energy and kinetic stress of ions cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->metric_tensor, 3, 0.0, pSPARC->Pm_ion, 3); - int count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - cblas_dscal(3 * pSPARC->nAtomv[ityp], pSPARC->Mass[ityp], &pSPARC->Pm_ion[count], 1); - count = count + 3 * pSPARC->nAtomv[ityp]; - } - // Calculate kinetic energy and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - pSPARC->KE_save = pSPARC->KE; + Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + // Calculating thermostat energies pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper @@ -1950,28 +1835,34 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); double ktemp = pSPARC->kB * pSPARC->thermos_T; - int count; + unsigned int count; //Initialize empty temporary matrices and vectors double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; double internal_stress_cartesian[9]; //Initialize some useful constants - double baro_const1; + double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; + NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; + NPT_NPHscaleVecs[3] = {0}; + NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } else{ + NPT_NPH_ANGLES = pSPARC->NPH_ANGLES; + NPT_NPHconstraintFlag = pSPARC->NPHconstraintFlag; + NPT_NPHscaleVecs[3] = {0}; + NPT_NPHscaleVecs[0] = pSPARC->NPHscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPHscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPHscaleVecs[2]; + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } double baro_const3 = 1.0 / baro_const1; + double thermo_const0 = 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0]; - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - - //Calculate_Ionic_particles_Kinetic_energy(pSPARC); - pSPARC->KE = pSPARC->KE_save; - + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// double Sa = 0.0; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) @@ -2019,12 +1910,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); } } else { if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC); + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); } } @@ -2035,33 +1926,18 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } + if (pSPARC->NPT_NPHscaleVecs[2] == 0 && pSPARC->NPT_NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } + if (pSPARC->NPT_NPHscaleVecs[0] == 0 && pSPARC->NPT_NPHscaleVecs[1] == 0 && pSPARC->NPT_NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) @@ -2076,26 +1952,20 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds to Eqn. 18i in Hernandez paper - double *ion_forces_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); - exit(EXIT_FAILURE); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->forces, 3, pSPARC->full_lattice, 3, 0.0, ion_forces_fractional, 3); - // Eqn. 18i: momentum += 0.5 * dt * S * D2C - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); count = 0; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); - count = count + 3 * pSPARC->nAtomv[ityp]; + unsigned int len = 3 * pSPARC->nAtomv[ityp]; + cblas_dcopy(len, &pSPARC->forces[count], 1, &pSPARC->ion_accel[count], 1); // Copy forces slice into ion_accel + cblas_dscal(len, 1.0 / Mass[ityp], &pSPARC->ion_accel[count], 1); // Scale by 1/mass + count += len; } - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); - + // Eqn. 18i: momentum += 0.5 * dt * S * D2C (but updating velocity in cartesian coordinates instead of momentum) + cblas_daxpy(3 * pSPARC->n_atom, thermo_const0, pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); + //Update the kinetic energy and kinetic stress of the Ionic particles + Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); + + //Calculate internal pressure for (int i = 0; i < 9; i++){ pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - pSPARC->internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); } @@ -2144,8 +2014,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, -2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress - // Obtain updated velocities in cartesian coordinates for use in MD_QOI function - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + cblas_dscal(3 * pSPARC->n_atom, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel, 1); int check1 = (pSPARC->PrintMDout == 1 && !rank); MD_QOI(pSPARC, avgvel, maxvel, mindis); Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file @@ -2158,20 +2027,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); - free(ion_forces_fractional); - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); - count = count + 3 * pSPARC->nAtomv[ityp]; - } + // This setup corresponds to Eqn. 18a in Hernandez paper (but updating velocity in cartesian coordinates instead of momentum; they are equivalent formulation as kinetic energy and kinetic stress is consistent with this change) + // Eqn. 18a: momentum += 0.5 * dt * S * D2C + cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + cblas_daxpy(3 * pSPARC->n_atom, thermo_const0, pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); // Now we update/Step-up the momenta of the barostat by dt/2 @@ -2180,32 +2041,16 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma Update_metric_tensor_momenta_iteratively_half_step(pSPARC); //Now impose the constraints on it - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } + if (pSPARC->NPT_NPHscaleVecs[2] == 0 && pSPARC->NPT_NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } + if (pSPARC->NPT_NPHscaleVecs[0] == 0 && pSPARC->NPT_NPHscaleVecs[1] == 0 && pSPARC->NPT_NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; } @@ -2272,34 +2117,35 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; //Eqn. 18e is implicitly solved in the below subroutine - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new, NPT_NPH_angles, NPT_NPHconstraintFlag); - //Before updating cell parameters, convert cartesian atomic position coordinates to fractional - double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, pSPARC->reciprocal_lattice, 3, 0.0, atom_pos_fractional, 3); - + //Before updating cell parameters, store the old reciprocal lattice + for (int i = 0; i < 9; i++) { temp_mat[i] = pSPARC->reciprocal_lattice[i];} //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor fetch_MD_cell_ingredients(pSPARC, true); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, temp_mat_b, 3); + // Now reconvert atomic positions to cartesian coordinates, accounting change in cell size/shape (remember this are still of previous step, they have yet to be updated) + double *atom_pos_update = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); //temporary array + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, temp_mat_b, 3, 0.0, atom_pos_update, 3); + cblas_dcopy(len, atom_pos_update, 1, pSPARC->atom_pos, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, temp_mat_b, 3, 0.0, atom_pos_update, 3); + cblas_dcopy(len, atom_pos_update, 1, pSPARC->ion_vel, 1); + free(atom_pos_update); + + //Update Atomic position in cartesian coordinates coordinates (Eqn. 18f in Hernandez paper) + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel, 1, pSPARC->atom_pos, 1); + //Update atomic positions and restore ionic velocities + cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); + //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - //Update Atomic position in fractional coordinates (Eqn. 18f in Hernandez paper) - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel_fractional, 1, atom_pos_fractional, 1); - - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, atom_pos_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->atom_pos, 3); - free(atom_pos_fractional); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); - - //Update atomic positions and restore ionic velocities - cblas_dscal(3 * pSPARC->n_atom, 1 / S_new, pSPARC->ion_vel, 1); //Update kinetic energy and kinetic stress based on new S pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); - pSPARC->KE_save = pSPARC->KE; for (int i = 0; i < 9; i++){ pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); } @@ -2314,7 +2160,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } -void compute_constraint_stress(SPARC_OBJ *pSPARC){ +void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants @@ -2339,68 +2185,37 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper } - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } + if (pSPARC->NPT_NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; } - else { - if (pSPARC->NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (pSPARC->NPT_NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } - else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (pSPARC->NPT_NPHscaleVecs[2] == 0 && pSPARC->NPT_NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; } + else if (pSPARC->NPT_NPHscaleVecs[0] == 0 && pSPARC->NPT_NPHscaleVecs[1] == 0 && pSPARC->NPT_NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + constraint_velocity[0] = gpig[0] * baro_const4; constraint_velocity[4] = gpig[4] * baro_const4; constraint_velocity[8] = gpig[8] * baro_const4; @@ -2426,7 +2241,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ } -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_angles, int NPT_NPHconstraintFlag){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants @@ -2502,67 +2317,35 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; + + if (pSPARC->NPT_NPH_ANGLES == 0){ + if (pSPARC->NPT_NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; new_metric_tensor[8] = new_metric_tensor[0]; - } + } - else if (pSPARC->NPTconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } + else if (pSPARC->NPT_NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; for (int i = 0; i < 9; i++){ temp_metric_tensor[i] = new_metric_tensor[i]; } - } - - else { - if (pSPARC->NPH_ANGLES == 0){ - if (pSPARC->NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } + } for (int i = 0; i < 9; i++){ pSPARC->metric_tensor[i] = temp_metric_tensor[i]; @@ -2575,7 +2358,6 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } } #endif - } diff --git a/src/md_working_Cartesian_velocity.c b/src/md_working_Cartesian_velocity.c index e71c1114..20f6ee8e 100644 --- a/src/md_working_Cartesian_velocity.c +++ b/src/md_working_Cartesian_velocity.c @@ -2049,17 +2049,16 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC) { //cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + int len = 3 * pSPARC->nAtomv[ityp]; + // Copy forces slice into ion_accel + cblas_dcopy(len, pSPARC->forces + count, 1, pSPARC->ion_accel + count, 1); + // Scale by 1/mass + cblas_dscal(len, 1.0 / Mass[ityp], pSPARC->ion_accel + count, 1); + count += len; } + cblas_daxpy(3 * pSPARC->n_atom, thermo_const0, pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); + //Update the kinetic energy of the Ionic particles Calculate_Ionic_particles_Kinetic_energy(pSPARC); From 3d1628fe45fc115449cdcba95feaede3fc438ea8 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 1 Apr 2026 11:25:19 -0400 Subject: [PATCH 37/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/MD_printing_refined_fractional.c | 235 +++++++++------------------ src/include/isddft.h | 3 +- src/include/md.h | 6 +- src/md.c | 41 +++-- 4 files changed, 102 insertions(+), 183 deletions(-) diff --git a/src/MD_printing_refined_fractional.c b/src/MD_printing_refined_fractional.c index 85150bea..0d8f260a 100644 --- a/src/MD_printing_refined_fractional.c +++ b/src/MD_printing_refined_fractional.c @@ -1957,11 +1957,21 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma double internal_stress_cartesian[9]; //Initialize some useful constants - double baro_const1; + double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; + NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; + NPT_NPHscaleVecs[3] = {0}; + NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } else{ + NPT_NPH_ANGLES = pSPARC->NPH_ANGLES; + NPT_NPHconstraintFlag = pSPARC->NPHconstraintFlag; + NPT_NPHscaleVecs[3] = {0}; + NPT_NPHscaleVecs[0] = pSPARC->NPHscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPHscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPHscaleVecs[2]; + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } double baro_const3 = 1.0 / baro_const1; @@ -2019,12 +2029,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); + compute_constraint_stress(pSPARC, NPT_NPHscaleVecs); } } else { if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC); + compute_constraint_stress(pSPARC, NPT_NPHscaleVecs); } } @@ -2035,34 +2045,20 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } + //Now impose the constraints on it + if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } + if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; @@ -2180,33 +2176,18 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma Update_metric_tensor_momenta_iteratively_half_step(pSPARC); //Now impose the constraints on it - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } + if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } + if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; } + // Now we update/Step-up the momenta of the thermostat by dt/2 @@ -2272,7 +2253,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; //Eqn. 18e is implicitly solved in the below subroutine - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new, NPT_NPH_ANGLES, NPT_NPHconstraintFlag); //Before updating cell parameters, convert cartesian atomic position coordinates to fractional double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); @@ -2314,7 +2295,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } -void compute_constraint_stress(SPARC_OBJ *pSPARC){ +void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants @@ -2345,62 +2326,33 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } + if (NPT_NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; } - else { - if (pSPARC->NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (NPT_NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } - else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; } + constraint_velocity[0] = gpig[0] * baro_const4; constraint_velocity[4] = gpig[4] * baro_const4; constraint_velocity[8] = gpig[8] * baro_const4; @@ -2426,7 +2378,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC){ } -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_ANGLES, int NPT_NPHconstraintFlag){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants @@ -2502,67 +2454,34 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; + if (NPT_NPH_ANGLES == 0){ + if (NPT_NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; new_metric_tensor[8] = new_metric_tensor[0]; - } + } - else if (pSPARC->NPTconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } + else if (NPT_NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; for (int i = 0; i < 9; i++){ temp_metric_tensor[i] = new_metric_tensor[i]; } - } - - else { - if (pSPARC->NPH_ANGLES == 0){ - if (pSPARC->NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } + } for (int i = 0; i < 9; i++){ pSPARC->metric_tensor[i] = temp_metric_tensor[i]; diff --git a/src/include/isddft.h b/src/include/isddft.h index 763a0109..708c723b 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -827,6 +827,7 @@ typedef struct _SPARC_OBJ{ double MD_dt; // MD time step [femtosecond] double mean_elec_T; // Average of electronic temperature double mean_ion_T; // Average of ionic temperature + double mean_internal_pressure; // Average of the internal pressure double mean_TE; // Average of total energy double mean_KE; // Average of kinetic energy of ions double mean_PE; // Average of electronic energy @@ -835,6 +836,7 @@ typedef struct _SPARC_OBJ{ double mean_TE_ext; // Average of extended system energy double std_elec_T; // Standard deviation of electronic temperature double std_ion_T; // Standard deviation of ionic temperature + double std_internal_pressure; // Standard deviation of the internal pressure double std_TE; // Standard deviation of total energy double std_KE; // Standard deviation of kinetic energy of ions double std_PE; // Standard deviation of electronic energy @@ -915,7 +917,6 @@ typedef struct _SPARC_OBJ{ double Hamiltonian_NPH; // Hamiltonian of NPH system double init_Hamil_NPT_NP; // initial Hamiltonian in NPT_NP ensemble double init_Hamil_NPH; // initial Hamiltonian in NPH ensemble - double mean_internal_pressure; double KE_save; //NPT_NP_specific double NPT_NP_qmass; // fictitious mass of thermostat (qmass) used in NPT_NP diff --git a/src/include/md.h b/src/include/md.h index 805d7a20..02c5b36c 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -173,11 +173,11 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC); void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC); -Calculate_Kinetic_energy_and_Kinetic_stress(SPARC_OBJ *pSPARC); +void Calculate_Kinetic_energy_and_Kinetic_stress(SPARC_OBJ *pSPARC); -void compute_constraint_stress(SPARC_OBJ *pSPARC); +void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs); -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new); +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_ANGLES, int NPT_NPHconstraintFlag); void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC); /** diff --git a/src/md.c b/src/md.c index 6ded0617..3982d0eb 100644 --- a/src/md.c +++ b/src/md.c @@ -1842,11 +1842,10 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma double internal_stress_cartesian[9]; //Initialize some useful constants - double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]; + double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3] = {0}; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; - NPT_NPHscaleVecs[3] = {0}; NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper @@ -1854,7 +1853,6 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma else{ NPT_NPH_ANGLES = pSPARC->NPH_ANGLES; NPT_NPHconstraintFlag = pSPARC->NPHconstraintFlag; - NPT_NPHscaleVecs[3] = {0}; NPT_NPHscaleVecs[0] = pSPARC->NPHscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPHscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPHscaleVecs[2]; baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper @@ -1926,14 +1924,15 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; } - if (pSPARC->NPT_NPHscaleVecs[2] == 0 && pSPARC->NPT_NPHconstraintFlag == 1){ + //Now impose the constraints on it + if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; pSPARC->Pm_metric_tensor[5] = 0; pSPARC->Pm_metric_tensor[2] = 0; } - if (pSPARC->NPT_NPHscaleVecs[0] == 0 && pSPARC->NPT_NPHscaleVecs[1] == 0 && pSPARC->NPT_NPHscaleVecs[2] == 1){ + if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } @@ -1954,10 +1953,11 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // This setup corresponds to Eqn. 18i in Hernandez paper cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); count = 0; + unsigned int len; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - unsigned int len = 3 * pSPARC->nAtomv[ityp]; + len = 3 * pSPARC->nAtomv[ityp]; cblas_dcopy(len, &pSPARC->forces[count], 1, &pSPARC->ion_accel[count], 1); // Copy forces slice into ion_accel - cblas_dscal(len, 1.0 / Mass[ityp], &pSPARC->ion_accel[count], 1); // Scale by 1/mass + cblas_dscal(len, 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_accel[count], 1); // Scale by 1/mass count += len; } // Eqn. 18i: momentum += 0.5 * dt * S * D2C (but updating velocity in cartesian coordinates instead of momentum) @@ -2041,19 +2041,18 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma Update_metric_tensor_momenta_iteratively_half_step(pSPARC); //Now impose the constraints on it - if (pSPARC->NPT_NPHscaleVecs[2] == 0 && pSPARC->NPT_NPHconstraintFlag == 1){ + if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; pSPARC->Pm_metric_tensor[5] = 0; pSPARC->Pm_metric_tensor[2] = 0; } - if (pSPARC->NPT_NPHscaleVecs[0] == 0 && pSPARC->NPT_NPHscaleVecs[1] == 0 && pSPARC->NPT_NPHscaleVecs[2] == 1){ + if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } - // Now we update/Step-up the momenta of the thermostat by dt/2 // This setup corresponds to Eqn. 18c in the Hernandez paper // Skip this step if doing NPH ensemble @@ -2117,7 +2116,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; //Eqn. 18e is implicitly solved in the below subroutine - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new, NPT_NPH_angles, NPT_NPHconstraintFlag); + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new, NPT_NPH_ANGLES, NPT_NPHconstraintFlag); //Before updating cell parameters, store the old reciprocal lattice for (int i = 0; i < 9; i++) { temp_mat[i] = pSPARC->reciprocal_lattice[i];} @@ -2127,9 +2126,9 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // Now reconvert atomic positions to cartesian coordinates, accounting change in cell size/shape (remember this are still of previous step, they have yet to be updated) double *atom_pos_update = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); //temporary array cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, temp_mat_b, 3, 0.0, atom_pos_update, 3); - cblas_dcopy(len, atom_pos_update, 1, pSPARC->atom_pos, 1); + cblas_dcopy(3 * pSPARC->n_atom, atom_pos_update, 1, pSPARC->atom_pos, 1); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, temp_mat_b, 3, 0.0, atom_pos_update, 3); - cblas_dcopy(len, atom_pos_update, 1, pSPARC->ion_vel, 1); + cblas_dcopy(3 * pSPARC->n_atom, atom_pos_update, 1, pSPARC->ion_vel, 1); free(atom_pos_update); //Update Atomic position in cartesian coordinates coordinates (Eqn. 18f in Hernandez paper) @@ -2190,20 +2189,20 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (pSPARC->NPT_NPHconstraintFlag == 4){ + if (NPT_NPHconstraintFlag == 4){ gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; gpig[4] = gpig[0]; gpig[8] = gpig[0]; } // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPT_NPHconstraintFlag == 1){ + else if (NPT_NPHconstraintFlag == 1){ gpig[0] = (gpig[0] + gpig[4]) / 2; gpig[4] = gpig[0]; } // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPT_NPHscaleVecs[2] == 0 && pSPARC->NPT_NPHconstraintFlag == 1){ + else if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ gpig[8] = 0; gpig[7] = 0; gpig[6] = 0; @@ -2211,7 +2210,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int gpig[2] = 0; } - else if (pSPARC->NPT_NPHscaleVecs[0] == 0 && pSPARC->NPT_NPHscaleVecs[1] == 0 && pSPARC->NPT_NPHscaleVecs[2] == 1){ + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ gpig[0] = 0; gpig[4] = 0; } @@ -2241,7 +2240,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int } -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_angles, int NPT_NPHconstraintFlag){ +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_ANGLES, int NPT_NPHconstraintFlag){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants @@ -2318,14 +2317,14 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } - if (pSPARC->NPT_NPH_ANGLES == 0){ - if (pSPARC->NPT_NPHconstraintFlag == 4){ + if (NPT_NPH_ANGLES == 0){ + if (NPT_NPHconstraintFlag == 4){ new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; new_metric_tensor[4] = new_metric_tensor[0]; new_metric_tensor[8] = new_metric_tensor[0]; } - else if (pSPARC->NPT_NPHconstraintFlag == 1){ + else if (NPT_NPHconstraintFlag == 1){ new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; new_metric_tensor[4] = new_metric_tensor[0]; } From 33946a1313fef27cddd12b1bd3064e07951325b3 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 1 Apr 2026 11:32:30 -0400 Subject: [PATCH 38/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/md.c b/src/md.c index 3982d0eb..310b46ba 100644 --- a/src/md.c +++ b/src/md.c @@ -1951,12 +1951,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds to Eqn. 18i in Hernandez paper - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + cblas_dcopy(3 * pSPARC->n_atom, pSPARC->forces, 1, pSPARC->ion_accel, 1); //copy the ion forces array into ion acceleration array count = 0; unsigned int len; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { len = 3 * pSPARC->nAtomv[ityp]; - cblas_dcopy(len, &pSPARC->forces[count], 1, &pSPARC->ion_accel[count], 1); // Copy forces slice into ion_accel cblas_dscal(len, 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_accel[count], 1); // Scale by 1/mass count += len; } From be8ca4b1f96bee0a8bc8eb1abcf8a47149b2509a Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 1 Apr 2026 12:10:47 -0400 Subject: [PATCH 39/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/md.c b/src/md.c index 310b46ba..8ecebecc 100644 --- a/src/md.c +++ b/src/md.c @@ -454,7 +454,8 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->SNOSE[1] = 0.0; pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; } - // pSPARC->thermos_Ti = pSPARC->elec_T; + + pSPARC->thermos_Ti = pSPARC->elec_T; pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! Calculate_ionic_stress(pSPARC); @@ -1495,11 +1496,13 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ //Compute metric_tensor (G) in real-space (not reciprocal space) cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // This is needed since, they will be used in function 'Cart2nonCart_transformMat' to update various quantities for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = ( pSPARC->LatUVec[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = ( pSPARC->LatUVec[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; + pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; } //Update LatUVec, Jacbdet, metricT, gradT, lapcT @@ -3134,25 +3137,25 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); } else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPH_bmass); fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); } - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); + fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); } else { fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] + fprintf(mdout,":LatVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); } - fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); - fprintf(mdout,":ROTATION_MATRIX: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] + fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI, axos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI ); + fprintf(mdout,":ROTATION_MATRIX: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); @@ -3346,6 +3349,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); + for (int i = 0; i < 3; i++){pSPARC->initialLatVecAngles[i] = cos(M_PI / 180 * pSPARC->initialLatVecAngles[i]);} } else if (strcmpi(str,":CELL:") == 0) { fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); } else if (strcmpi(str,":LatUVec:") == 0) { From 3149b02fca2c87f014870bf863052afbf874426e Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 1 Apr 2026 12:15:26 -0400 Subject: [PATCH 40/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/md.c b/src/md.c index 8ecebecc..f7be1f08 100644 --- a/src/md.c +++ b/src/md.c @@ -1603,8 +1603,8 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ //Update LATVEC_SCALE and LatVec for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = ( pSPARC->LatUVec[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = ( pSPARC->LatUVec[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; + pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; } if (pSPARC->Flag_latvec_scale == 1){ // LATVEC_SCALE accounts for change in lengths pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; @@ -3154,7 +3154,7 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); } - fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI, axos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI ); + fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI ); fprintf(mdout,":ROTATION_MATRIX: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); From 1624d56e0bb88df40f7ebca5766ae953cf960404 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 1 Apr 2026 12:57:33 -0400 Subject: [PATCH 41/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 92 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 21 deletions(-) diff --git a/src/md.c b/src/md.c index f7be1f08..21097d28 100644 --- a/src/md.c +++ b/src/md.c @@ -455,7 +455,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; } - pSPARC->thermos_Ti = pSPARC->elec_T; + //pSPARC->thermos_Ti = pSPARC->elec_T; pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! Calculate_ionic_stress(pSPARC); @@ -2867,10 +2867,12 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; } + // Compute Ionic stress/pressure - - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + } // Calculate_stress(pSPARC); #ifdef DEBUG @@ -3140,9 +3142,9 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPH_bmass); fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); } - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + fprintf(mdout,":lattice_avg_velo: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice if (pSPARC->Flag_latvec_scale == 0){ fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] @@ -3161,16 +3163,26 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * 29421.02648438959); fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * 29421.02648438959 - ,pSPARC->stress_external[1] * 29421.02648438959 - ,pSPARC->stress_external[2] * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); + ,pSPARC->stress_external[1] * 29421.02648438959 + ,pSPARC->stress_external[2] * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); } // Print temperature fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - + fprintf(mdout,":TELST(K): %.15g\n", pSPARC->mean_elec_T); + fprintf(mdout,":TIOST(K): %.15g\n", pSPARC->mean_ion_T); + fprintf(mdout,":PREST(K): %.15g\n", pSPARC->mean_internal_pressure); + fprintf(mdout,":TENST(K): %.15g\n", pSPARC->mean_TE); + fprintf(mdout,":KENST(K): %.15g\n", pSPARC->mean_KE); + fprintf(mdout,":FENST(K): %.15g\n", pSPARC->mean_PE); + fprintf(mdout,":UENST(K): %.15g\n", pSPARC->mean_U); + fprintf(mdout,":TSENST(K): %.15g\n", pSPARC->mean_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext); + } fclose(mdout); } } @@ -3211,16 +3223,16 @@ void RestartMD(SPARC_OBJ *pSPARC) { if(pSPARC->RestartFlag == 1){ // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 10)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56)) * sizeof(double); + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56 + 10)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52)) * sizeof(double); + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52 + 10)) * sizeof(double); } else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 11) * sizeof(double); } } else if(pSPARC->RestartFlag == -1) @@ -3255,6 +3267,26 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->ion_T); else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TELST(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->mean_elec_T); + else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); + else if (strcmpi(str,":PREST(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); + else if (strcmpi(str,":TENST(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->mean_TE); + else if (strcmpi(str,":KENST(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->mean_KE); + else if (strcmpi(str,":FENST(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->mean_PE); + else if (strcmpi(str,":UENST(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->mean_U); + else if (strcmpi(str,":TSENST(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->mean_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + if (strcmpi(str,":TSENST(K):") == 0 && pSPARC->RestartFlag == 1); + fscanf(rst_fp,"%lf", &pSPARC->mean_TE_ext) + } if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { if (strcmpi(str,":NPT_NH_QMASS:") == 0) { fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); @@ -3395,8 +3427,17 @@ void RestartMD(SPARC_OBJ *pSPARC) { if(pSPARC->RestartFlag == 1){ MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->mean_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } @@ -3467,8 +3508,17 @@ void RestartMD(SPARC_OBJ *pSPARC) { if(pSPARC->RestartFlag == 1){ MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); } From c9aaa3e9397e23e3bb06a15154729eb8d45daa01 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 1 Apr 2026 13:43:45 -0400 Subject: [PATCH 42/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 136 +++++++++++++++++++++++++------------------------------ 1 file changed, 61 insertions(+), 75 deletions(-) diff --git a/src/md.c b/src/md.c index 21097d28..d94d0dc8 100644 --- a/src/md.c +++ b/src/md.c @@ -203,10 +203,6 @@ void main_MD(SPARC_OBJ *pSPARC) { fclose(pSPARC->fp_energy); pSPARC->fp_energy = NULL; } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ - free(pSPARC->ion_vel_fractional); - free(pSPARC->Pm_ion); - } } /** @@ -364,23 +360,15 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); fflush(pSPARC->fp_energy); } - pSPARC->KE_save = 0.0; fetch_MD_cell_ingredients(pSPARC, false); - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ if (!rank) { @@ -438,15 +426,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; if(strcmpi(pSPARC->MDMeth,"NPH")){ pSPARC->NPT_NP_qmass = 0; @@ -457,19 +439,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { //pSPARC->thermos_Ti = pSPARC->elec_T; pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - - Calculate_ionic_stress(pSPARC); - - pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); - exit(EXIT_FAILURE); - } - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); - exit(EXIT_FAILURE); - } + //Calculate_ionic_stress(pSPARC); } if(pSPARC->RestartFlag == 0){ @@ -580,9 +550,11 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { #ifdef DEBUG // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; + if (pSPARC->RestartFlag == 0){ + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; + } #endif } @@ -1789,8 +1761,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ transpose_and_add(pSPARC->Pm_metric_tensor); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3 * baro_const2, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; @@ -1865,13 +1836,13 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; + double factor; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) if (pSPARC->NPT_NP_qmass > 0){ pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; - pSPARC->SNOSE[1] += 0.5 * Sa * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; + factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; + pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; #ifdef DEBUG if (rank == 0) { printf("Sa is %12.9f\n", Sa); @@ -2060,9 +2031,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // This setup corresponds to Eqn. 18c in the Hernandez paper // Skip this step if doing NPH ensemble if (pSPARC->NPT_NP_qmass > 0){ - double factor; factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - #ifdef DEBUG if (rank == 0) printf("factor is %12.9f\n", factor); @@ -2071,7 +2040,6 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if (rank == 0) printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); } - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); #ifdef DEBUG if (rank == 0) @@ -3170,16 +3138,16 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { ,pSPARC->stress_external[5] * 29421.02648438959); } // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - fprintf(mdout,":TELST(K): %.15g\n", pSPARC->mean_elec_T); - fprintf(mdout,":TIOST(K): %.15g\n", pSPARC->mean_ion_T); - fprintf(mdout,":PREST(K): %.15g\n", pSPARC->mean_internal_pressure); - fprintf(mdout,":TENST(K): %.15g\n", pSPARC->mean_TE); - fprintf(mdout,":KENST(K): %.15g\n", pSPARC->mean_KE); - fprintf(mdout,":FENST(K): %.15g\n", pSPARC->mean_PE); - fprintf(mdout,":UENST(K): %.15g\n", pSPARC->mean_U); - fprintf(mdout,":TSENST(K): %.15g\n", pSPARC->mean_Entropy); + fprintf(mdout,":TEL(K): %18.10E %18.10E\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %18.10E %18.10E\n", pSPARC->ion_T); + fprintf(mdout,":TELST(K): %18.10E %18.10E\n", pSPARC->mean_elec_T); + fprintf(mdout,":TIOST(K): %18.10E %18.10E\n", pSPARC->mean_ion_T); + fprintf(mdout,":PREST(K): %18.10E %18.10E\n", pSPARC->mean_internal_pressure); + fprintf(mdout,":TENST(K): %18.10E %18.10E\n", pSPARC->mean_TE); + fprintf(mdout,":KENST(K): %18.10E %18.10E\n", pSPARC->mean_KE); + fprintf(mdout,":FENST(K): %18.10E %18.10E\n", pSPARC->mean_PE); + fprintf(mdout,":UENST(K): %18.10E %18.10E\n", pSPARC->mean_U); + fprintf(mdout,":TSENST(K): %18.10E %18.10E\n", pSPARC->mean_Entropy); if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ fprintf(mdout,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext); } @@ -3223,16 +3191,16 @@ void RestartMD(SPARC_OBJ *pSPARC) { if(pSPARC->RestartFlag == 1){ // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 10)) * sizeof(double); + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 20)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56 + 10)) * sizeof(double); + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56 + 20)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52 + 10)) * sizeof(double); + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52 + 20)) * sizeof(double); } else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 11) * sizeof(double); + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 22) * sizeof(double); } } else if(pSPARC->RestartFlag == -1) @@ -3268,24 +3236,24 @@ void RestartMD(SPARC_OBJ *pSPARC) { else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); else if (strcmpi(str,":TELST(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->mean_elec_T); + fscanf(rst_fp,"%lf", &pSPARC->mean_elec_T); fscanf(rst_fp,"%lf", &pSPARC->std_elec_T); else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); + fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); else if (strcmpi(str,":PREST(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); + fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); else if (strcmpi(str,":TENST(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->mean_TE); + fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); else if (strcmpi(str,":KENST(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->mean_KE); + fscanf(rst_fp,"%lf", &pSPARC->mean_KE); fscanf(rst_fp,"%lf", &pSPARC->std_KE); else if (strcmpi(str,":FENST(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->mean_PE); + fscanf(rst_fp,"%lf", &pSPARC->mean_PE); fscanf(rst_fp,"%lf", &pSPARC->std_PE); else if (strcmpi(str,":UENST(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->mean_U); + fscanf(rst_fp,"%lf", &pSPARC->mean_U); fscanf(rst_fp,"%lf", &pSPARC->std_U); else if (strcmpi(str,":TSENST(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->mean_Entropy); + fscanf(rst_fp,"%lf", &pSPARC->mean_Entropy); fscanf(rst_fp,"%lf", &pSPARC->std_Entropy); if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ if (strcmpi(str,":TSENST(K):") == 0 && pSPARC->RestartFlag == 1); - fscanf(rst_fp,"%lf", &pSPARC->mean_TE_ext) + fscanf(rst_fp,"%lf", &pSPARC->mean_TE_ext); fscanf(rst_fp,"%lf", &pSPARC->std_TE_ext); } if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { if (strcmpi(str,":NPT_NH_QMASS:") == 0) { @@ -3428,15 +3396,24 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->mean_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->mean_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->mean_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->mean_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->mean_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->mean_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->mean_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ MPI_Pack(&pSPARC->mean_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); @@ -3509,18 +3486,27 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); } else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); From 59917194177caa6338f137b7b918f3a602d6284e Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 1 Apr 2026 16:34:50 -0400 Subject: [PATCH 43/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/MD_printing_refined_fractional.c | 169 ++++++++++++++++++--------- src/md.c | 93 ++++++--------- 2 files changed, 149 insertions(+), 113 deletions(-) diff --git a/src/MD_printing_refined_fractional.c b/src/MD_printing_refined_fractional.c index 0d8f260a..f29f7dfd 100644 --- a/src/MD_printing_refined_fractional.c +++ b/src/MD_printing_refined_fractional.c @@ -372,15 +372,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ if (!rank) { @@ -438,15 +432,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; if(strcmpi(pSPARC->MDMeth,"NPH")){ pSPARC->NPT_NP_qmass = 0; @@ -579,9 +567,11 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { #ifdef DEBUG // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; + if (pSPARC->RestartFlag == 0){ + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; + } #endif } @@ -2745,6 +2735,7 @@ void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { } + /* @ brief: function to write all relevant DFT quantities generated during MD simulation */ @@ -2908,7 +2899,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":STRESS:\n"); double stress_e[6]; // electronic stress for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + stress_e[i] = pSPARC->stress[i]; // stress_i or ionic stress function is never called in NPT_NP or NPH ensemble, so pSPARC->stress does not include contribution from it, and thus no need to subtract stress_i from pSPARC->stress, as done in other ensembles PrintStress (pSPARC, stress_e, output_md); fprintf(output_md,":TOTSTRESS:\n"); //Print total internal stress accouting for the constraints in NPT_NP or NPH ensemble temp_stress[0] = pSPARC->total_internal_stress[0]; temp_stress[1] = pSPARC->total_internal_stress[1]; temp_stress[2] = pSPARC->total_internal_stress[2]; @@ -3002,16 +2993,18 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; } + // Compute Ionic stress/pressure - - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + } // Calculate_stress(pSPARC); #ifdef DEBUG // MD Statistics double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; mean_Te_old = pSPARC->mean_elec_T; mean_Ti_old = pSPARC->mean_ion_T; mean_TE_old = pSPARC->mean_TE; @@ -3272,40 +3265,50 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); } else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPH_bmass); fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); } - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + fprintf(mdout,":lattice_avg_velo: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); + fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); } else { fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] + fprintf(mdout,":LatVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); } - fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); - fprintf(mdout,":ROTATION_MATRIX: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] + fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI ); + fprintf(mdout,":ROTATION_MATRIX: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * 29421.02648438959); fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * 29421.02648438959 - ,pSPARC->stress_external[1] * 29421.02648438959 - ,pSPARC->stress_external[2] * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); + ,pSPARC->stress_external[1] * 29421.02648438959 + ,pSPARC->stress_external[2] * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); } // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - + fprintf(mdout,":TEL(K): %18.10E\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %18.10E\n", pSPARC->ion_T); + fprintf(mdout,":TELST(K): %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(mdout,":TIOST(K): %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(mdout,":PREST(Gpa): %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(mdout,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(mdout,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(mdout,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(mdout,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(mdout,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } fclose(mdout); } } @@ -3346,16 +3349,16 @@ void RestartMD(SPARC_OBJ *pSPARC) { if(pSPARC->RestartFlag == 1){ // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 20)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56)) * sizeof(double); + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56 + 20)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52)) * sizeof(double); + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52 + 20)) * sizeof(double); } else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 22) * sizeof(double); } } else if(pSPARC->RestartFlag == -1) @@ -3390,6 +3393,28 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->ion_T); else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TELST(K):") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_elec_T); fscanf(rst_fp,"%lf", &pSPARC->std_elec_T); + }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); + }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); + }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); + }else if (strcmpi(str,":KENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_KE); fscanf(rst_fp,"%lf", &pSPARC->std_KE); + }else if (strcmpi(str,":FENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_PE); fscanf(rst_fp,"%lf", &pSPARC->std_PE); + }else if (strcmpi(str,":UENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_U); fscanf(rst_fp,"%lf", &pSPARC->std_U); + }else if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_Entropy); fscanf(rst_fp,"%lf", &pSPARC->std_Entropy); + } + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_TE_ext); fscanf(rst_fp,"%lf", &pSPARC->std_TE_ext); + } + } if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { if (strcmpi(str,":NPT_NH_QMASS:") == 0) { fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); @@ -3484,6 +3509,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); + for (int i = 0; i < 3; i++){pSPARC->initialLatVecAngles[i] = cos(M_PI / 180 * pSPARC->initialLatVecAngles[i]);} } else if (strcmpi(str,":CELL:") == 0) { fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); } else if (strcmpi(str,":LatUVec:") == 0) { @@ -3529,8 +3555,26 @@ void RestartMD(SPARC_OBJ *pSPARC) { if(pSPARC->RestartFlag == 1){ MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->mean_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } @@ -3601,10 +3645,28 @@ void RestartMD(SPARC_OBJ *pSPARC) { if(pSPARC->RestartFlag == 1){ MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); } else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); @@ -3663,6 +3725,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } + /* @ brief: function to rename the restart file */ diff --git a/src/md.c b/src/md.c index d94d0dc8..b4360007 100644 --- a/src/md.c +++ b/src/md.c @@ -390,17 +390,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->thermos_Ti = pSPARC->ion_T; pSPARC->thermos_T = pSPARC->thermos_Ti; - - pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); - exit(EXIT_FAILURE); - } - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); - exit(EXIT_FAILURE); - } + } else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart int rank; @@ -1402,9 +1392,9 @@ Physical Review B 55.14 (1997): 8733. void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - + //Calculate initial hamitonian if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { NPT_NP_and_NPH_init_hamiltonian(pSPARC); @@ -1625,7 +1615,7 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell@Rotation_matrix.T = old_cell; + //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell = old_cell@rotation_matrix; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); //Initiating cell lattice vectors velocity as zero @@ -1672,25 +1662,6 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double vector[3]={0.0}; - pSPARC->KE = 0.0; - - int count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - pSPARC->KE += pSPARC->Mass[ityp] * ( pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count*3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count*3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count*3 + 2] ); - count++; - } - } - - pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); -} - - void Calculate_Kinetic_energy_and_Kinetic_stress(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -1845,7 +1816,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; #ifdef DEBUG if (rank == 0) { - printf("Sa is %12.9f\n", Sa); + printf("factor Eqn.18G is %12.9f\n", factor); printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); } #endif @@ -1858,9 +1829,9 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3] - pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5] - pSPARC->stress_i[5]; - internal_stress_cartesian[1] = pSPARC->stress[1] - pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1] - pSPARC->stress_i[1]; - internal_stress_cartesian[5] = pSPARC->stress[4] - pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4] - pSPARC->stress_i[4]; + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat_b, 3); cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, pSPARC->reciprocal_lattice, 3, temp_mat_b, 3, 0.0, pSPARC->internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 @@ -2034,7 +2005,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; #ifdef DEBUG if (rank == 0) - printf("factor is %12.9f\n", factor); + printf("factor Eqn.18c is %12.9f\n", factor); #endif if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ if (rank == 0) @@ -2741,7 +2712,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":STRESS:\n"); double stress_e[6]; // electronic stress for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + stress_e[i] = pSPARC->stress[i]; // stress_i or ionic stress function is never called in NPT_NP or NPH ensemble, so pSPARC->stress does not include contribution from it, and thus no need to subtract stress_i from pSPARC->stress, as done in other ensembles PrintStress (pSPARC, stress_e, output_md); fprintf(output_md,":TOTSTRESS:\n"); //Print total internal stress accouting for the constraints in NPT_NP or NPH ensemble temp_stress[0] = pSPARC->total_internal_stress[0]; temp_stress[1] = pSPARC->total_internal_stress[1]; temp_stress[2] = pSPARC->total_internal_stress[2]; @@ -2846,7 +2817,7 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { #ifdef DEBUG // MD Statistics double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; mean_Te_old = pSPARC->mean_elec_T; mean_Ti_old = pSPARC->mean_ion_T; mean_TE_old = pSPARC->mean_TE; @@ -3138,18 +3109,18 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { ,pSPARC->stress_external[5] * 29421.02648438959); } // Print temperature - fprintf(mdout,":TEL(K): %18.10E %18.10E\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %18.10E %18.10E\n", pSPARC->ion_T); - fprintf(mdout,":TELST(K): %18.10E %18.10E\n", pSPARC->mean_elec_T); - fprintf(mdout,":TIOST(K): %18.10E %18.10E\n", pSPARC->mean_ion_T); - fprintf(mdout,":PREST(K): %18.10E %18.10E\n", pSPARC->mean_internal_pressure); - fprintf(mdout,":TENST(K): %18.10E %18.10E\n", pSPARC->mean_TE); - fprintf(mdout,":KENST(K): %18.10E %18.10E\n", pSPARC->mean_KE); - fprintf(mdout,":FENST(K): %18.10E %18.10E\n", pSPARC->mean_PE); - fprintf(mdout,":UENST(K): %18.10E %18.10E\n", pSPARC->mean_U); - fprintf(mdout,":TSENST(K): %18.10E %18.10E\n", pSPARC->mean_Entropy); + fprintf(mdout,":TEL(K): %18.10E\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %18.10E\n", pSPARC->ion_T); + fprintf(mdout,":TELST(K): %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(mdout,":TIOST(K): %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(mdout,":PREST(Gpa): %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(mdout,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(mdout,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(mdout,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(mdout,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(mdout,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext); + fprintf(mdout,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); } fclose(mdout); } @@ -3235,25 +3206,27 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->ion_T); else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TELST(K):") == 0 && pSPARC->RestartFlag == 1) + else if (strcmpi(str,":TELST(K):") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_elec_T); fscanf(rst_fp,"%lf", &pSPARC->std_elec_T); - else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1) + }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); - else if (strcmpi(str,":PREST(K):") == 0 && pSPARC->RestartFlag == 1) + }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); - else if (strcmpi(str,":TENST(K):") == 0 && pSPARC->RestartFlag == 1) + }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); - else if (strcmpi(str,":KENST(K):") == 0 && pSPARC->RestartFlag == 1) + }else if (strcmpi(str,":KENST:") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_KE); fscanf(rst_fp,"%lf", &pSPARC->std_KE); - else if (strcmpi(str,":FENST(K):") == 0 && pSPARC->RestartFlag == 1) + }else if (strcmpi(str,":FENST:") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_PE); fscanf(rst_fp,"%lf", &pSPARC->std_PE); - else if (strcmpi(str,":UENST(K):") == 0 && pSPARC->RestartFlag == 1) + }else if (strcmpi(str,":UENST:") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_U); fscanf(rst_fp,"%lf", &pSPARC->std_U); - else if (strcmpi(str,":TSENST(K):") == 0 && pSPARC->RestartFlag == 1) + }else if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_Entropy); fscanf(rst_fp,"%lf", &pSPARC->std_Entropy); + } if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - if (strcmpi(str,":TSENST(K):") == 0 && pSPARC->RestartFlag == 1); + if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_TE_ext); fscanf(rst_fp,"%lf", &pSPARC->std_TE_ext); + } } if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { if (strcmpi(str,":NPT_NH_QMASS:") == 0) { From 4ea7d446206ccb24fccc44d104bdd4f3306d9bba Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Wed, 1 Apr 2026 17:51:02 -0400 Subject: [PATCH 44/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/MD_printing_refined_cartesian.c | 3554 ++++++++++++++++++++++++++ src/MD_printing_refined_fractional.c | 4 +- src/md.c | 384 ++- 3 files changed, 3843 insertions(+), 99 deletions(-) create mode 100644 src/MD_printing_refined_cartesian.c diff --git a/src/MD_printing_refined_cartesian.c b/src/MD_printing_refined_cartesian.c new file mode 100644 index 00000000..f34b3880 --- /dev/null +++ b/src/MD_printing_refined_cartesian.c @@ -0,0 +1,3554 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include +#include +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + pSPARC->internal_pressure = 0; + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); +#ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); +#endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) + NPT_NP_and_NPH(pSPARC, output_md, avgvel, maxvel, mindis); //The last four arguments: output_md, avgvel, maxvel and mindis are only passed so as to facilitate calling 'MD_QOI' or 'Print_fullMD' function from within NPT_NP or NPH subroutines + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + } + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); +#ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); +#endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; + } +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + if (pSPARC->Flag_latvec_scale == 1){ + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else{ + pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; + } + + pSPARC->maxTimeIter = 100; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); + printf("herere"); + exit(EXIT_FAILURE); + } + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + if(pSPARC->NPH_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); + printf("he1"); + exit(EXIT_FAILURE); + } + } + } + + if (rank == 0) { + // "w" creates a new file; "a" appends to an existing one. + pSPARC->fp_energy = fopen("MD_energies_NPH2.log", "w"); + + if (pSPARC->fp_energy == NULL) { + fprintf(stderr, "Error: Could not open energy log file!\n"); + exit(EXIT_FAILURE); + } + + // Optional: Print a header to make the file readable in Excel/Python + fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", + "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); + fflush(pSPARC->fp_energy); + } + fetch_MD_cell_ingredients(pSPARC, false); + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble\n"); + } + } + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; //This is computed in function: 'fetch_MD_cell_ingredients_restart' below + + if (pSPARC->Flag_latvec_scale == 1){ + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else{ + pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; + } + pSPARC->maxTimeIter = 100; + + pSPARC->KE_save = 0.0; + fetch_MD_cell_ingredients_restart(pSPARC); + + + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPH")){ + pSPARC->NPT_NP_qmass = 0; + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + } + + //pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + //Calculate_ionic_stress(pSPARC); + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + if (pSPARC->RestartFlag == 0){ + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; + } +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant. +Also performs NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant. NPH in this scheme is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference for NPT_NP and NPH: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Additional Reference for NPH: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine + NPT_NPH_main(pSPARC, output_md, avgvel, maxvel, mindis); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); + #endif +} + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ + +void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + + + // This is needed since, they will be used in function 'Cart2nonCart_transformMat' to update various quantities + for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles + pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; + } + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat(pSPARC); + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + +} + +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Cosine of Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; + + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + + //Update LATVEC_SCALE and LatVec + for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles + pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; + } + if (pSPARC->Flag_latvec_scale == 1){ // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + } + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT + Cart2nonCart_transformMat(pSPARC); + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + } + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell = old_cell@rotation_matrix; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate the velocity of cell lattice vectors (only useful in 1st MD step (start afresh or restart)) + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } + + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Kinetic_energy_and_Kinetic_stress(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+2] * pSPARC->ion_vel[count*3+2]; + count++; + } + } + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); + + pSPARC->KE = pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[4] + pSPARC->kinetic_stress[8]; + + //Convert kinetic stress to fractional coordinates + double temp_mat1[9]; + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat1, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat1, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else { + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + double ktemp = pSPARC->kB * pSPARC->thermos_T; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + + // // Calculate kinetic energy and kinetic stress of ions + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); + Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + cblas_dscal(pSPARC->n_atom * 3, 1.0 / pSPARC->SNOSE[2], pSPARC->ion_vel, 1); + pSPARC->KE_save = pSPARC->KE; + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3 * baro_const2, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + + double sumAllHamilTerms; + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// + + //Initialize constraint stress to 0 + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; + } +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp = pSPARC->kB * pSPARC->thermos_T; + unsigned int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; + + //Initialize some useful constants + double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3] = {0}; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; + NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; + NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; + + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + NPT_NPH_ANGLES = pSPARC->NPH_ANGLES; + NPT_NPHconstraintFlag = pSPARC->NPHconstraintFlag; + NPT_NPHscaleVecs[0] = pSPARC->NPHscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPHscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPHscaleVecs[2]; + + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const3 = 1.0 / baro_const1; + double thermo_const0 = 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0]; + + pSPARC->KE = pSPARC->KE_save; + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double factor; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; + pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; + #ifdef DEBUG + if (rank == 0) { + printf("factor Eqn.18G is %12.9f\n", factor); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + } + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat_b, 3); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, pSPARC->reciprocal_lattice, 3, temp_mat_b, 3, 0.0, pSPARC->internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = (pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); + } + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); + } + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = pSPARC->internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + //Now impose the constraints on it + if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + cblas_dcopy(3 * pSPARC->n_atom, pSPARC->forces, 1, pSPARC->ion_accel, 1); //copy the ion forces array into ion acceleration array + count = 0; + unsigned int len; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + len = 3 * pSPARC->nAtomv[ityp]; + cblas_dscal(len, 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_accel[count], 1); // Scale by 1/mass + count += len; + } + // Eqn. 18i: momentum += 0.5 * dt * S * D2C (but updating velocity in cartesian coordinates instead of momentum) + cblas_daxpy(3 * pSPARC->n_atom, thermo_const0, pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); + //Update the kinetic energy and kinetic stress of the Ionic particles + Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); + + //Calculate internal pressure + for (int i = 0; i < 9; i++){ + pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - pSPARC->internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); + + //Update Hamiltonian + double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms ; + } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } + } + #endif + + // For printing, convert the total internal stress and the kinetic stress to cartesian coordinates + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->total_internal_stress, 3); //Mutliplied by 2 so as to remove the effect of previous divisions by 2 in the kinetic_stress, internal_stress_fractional + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, -2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress + + cblas_dscal(3 * pSPARC->n_atom, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + pSPARC->KE_save = pSPARC->KE; + int check1 = (pSPARC->PrintMDout == 1 && !rank); + MD_QOI(pSPARC, avgvel, maxvel, mindis); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + pSPARC->KE = pSPARC->KE_save; + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper (but updating velocity in cartesian coordinates instead of momentum; they are equivalent formulation as kinetic energy and kinetic stress is consistent with this change) + // Eqn. 18a: momentum += 0.5 * dt * S * D2C + cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + cblas_daxpy(3 * pSPARC->n_atom, thermo_const0, pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC); + + //Now impose the constraints on it + if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + #ifdef DEBUG + if (rank == 0) + printf("factor Eqn.18c is %12.9f\n", factor); + #endif + if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + } + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp - S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + printf("%15.7f \n", S_new); + printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + + //Eqn. 18e is implicitly solved in the below subroutine + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new, NPT_NPH_ANGLES, NPT_NPHconstraintFlag); + + //Before updating cell parameters, store the old reciprocal lattice + for (int i = 0; i < 9; i++) { temp_mat[i] = pSPARC->reciprocal_lattice[i];} + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, temp_mat_b, 3); + // Now reconvert atomic positions to cartesian coordinates, accounting change in cell size/shape (remember this are still of previous step, they have yet to be updated) + double *atom_pos_update = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); //temporary array + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, temp_mat_b, 3, 0.0, atom_pos_update, 3); + cblas_dcopy(3 * pSPARC->n_atom, atom_pos_update, 1, pSPARC->atom_pos, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, temp_mat_b, 3, 0.0, atom_pos_update, 3); + cblas_dcopy(3 * pSPARC->n_atom, atom_pos_update, 1, pSPARC->ion_vel, 1); + free(atom_pos_update); + + //Update Atomic position in cartesian coordinates coordinates (Eqn. 18f in Hernandez paper) + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel, 1, pSPARC->atom_pos, 1); + //Update atomic positions and restore ionic velocities + cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); + + + //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + //Update kinetic energy and kinetic stress based on new S + pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); + } + pSPARC->KE_save = pSPARC->KE; + // Update SNOSE[0] to S_new + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_new; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// +} + + +void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (NPT_NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (NPT_NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_ANGLES, int NPT_NPHconstraintFlag){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); + } + + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + + + if (NPT_NPH_ANGLES == 0){ + if (NPT_NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (NPT_NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } + } + #endif +} + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-12; // tolerance criterion for checking convergence + double baro_const0, baro_const3, baro_const5; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + + } + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++) + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif + } +} + + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); + fprintf(output_md,":Desc_SNOSE[0]: Position variable of the thermostat\n"); + fprintf(output_md,":Desc_SNOSE[1]: Velocity variable of the thermostat\n"); + } else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell expansion). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated as: kinetic_stress (positive convention) - electronic stress - constraint stress; as per (E. Hernandez, 2001) paper + } + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_TOTSTRESS: Total internal pressure (also accounting pressure due to any constraint on cell expansion). Unit=GPa \n"); + } + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); + fprintf(output_md,":SNOSE[0]:%18.10E \n", pSPARC->SNOSE[0]); + fprintf(output_md,":SNOSE[1]:%18.10E \n", pSPARC->SNOSE[1]); + } if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x / pSPARC->initialLatVecLength[0], pSPARC->range_y / pSPARC->initialLatVecLength[1], pSPARC->range_z / pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + else{ //Trigger NPT_NP or NPH ensemble stress printing + fprintf(output_md,":STRIO:\n"); + double temp_stress[6]; + temp_stress[0] = pSPARC->kinetic_stress[0]; temp_stress[1] = pSPARC->kinetic_stress[1]; temp_stress[2] = pSPARC->kinetic_stress[2]; + temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[7]; + PrintStress (pSPARC, temp_stress, output_md); //Print kinetic stress as defined in the (E. Hernandez, 2001) paper + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i]; // stress_i or ionic stress function is never called in NPT_NP or NPH ensemble, so pSPARC->stress does not include contribution from it, and thus no need to subtract stress_i from pSPARC->stress, as done in other ensembles + PrintStress (pSPARC, stress_e, output_md); + fprintf(output_md,":TOTSTRESS:\n"); //Print total internal stress accouting for the constraints in NPT_NP or NPH ensemble + temp_stress[0] = pSPARC->total_internal_stress[0]; temp_stress[1] = pSPARC->total_internal_stress[1]; temp_stress[2] = pSPARC->total_internal_stress[2]; + temp_stress[3] = pSPARC->total_internal_stress[4]; temp_stress[4] = pSPARC->total_internal_stress[5]; temp_stress[5] = pSPARC->total_internal_stress[7]; + PrintStress (pSPARC, temp_stress, output_md); + } + } + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i) * CONST_HA_BOHR3_GPA); + } + else{ //Trigger NPT_NP or NPH ensemble stress printing + double ion_kinetic_pressure; + ion_kinetic_pressure = -1.0 / 3.0 * (pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[1] + pSPARC->kinetic_stress[2]); //Kinetic stress is already multiplied by 2 + fprintf(output_md,":PRESIO: %18.10E\n", ion_kinetic_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->internal_pressure - ion_kinetic_pressure) * CONST_HA_BOHR3_GPA); + fprintf(output_md,":TOTPRES: %18.10E\n", pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); //Also accounts for pressure due to constraint stress + } + + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig * CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":PREST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the quantities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE / pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + + // Compute Ionic stress/pressure + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + } + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old; + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + mean_internal_pressure_old = pSPARC->mean_internal_pressure; + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_internal_pressure = sqrt(fabs( ((pow(pSPARC->std_internal_pressure,2.0) + pow(mean_internal_pressure_old,2.0)) * (Count - 1) + pow(pSPARC->internal_pressure,2.0))/Count - pow(pSPARC->mean_internal_pressure,2.0) )); + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(9, sizeof(double)); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + printf("\n"); + printf("\n"); + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP or NPH ensemble + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":NPT_NP_SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep + fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep + fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPH_bmass); + fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + fprintf(mdout,":lattice_avg_velo: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] + , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] + , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); + fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] + , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] + , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] + , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] + , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); + } + fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI ); + fprintf(mdout,":ROTATION_MATRIX: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] + , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] + , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * 29421.02648438959); + fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * 29421.02648438959 + ,pSPARC->stress_external[1] * 29421.02648438959 + ,pSPARC->stress_external[2] * 29421.02648438959 + ,pSPARC->stress_external[3] * 29421.02648438959 + ,pSPARC->stress_external[4] * 29421.02648438959 + ,pSPARC->stress_external[5] * 29421.02648438959); + } + // Print temperature + fprintf(mdout,":TEL(K): %18.10E\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %18.10E\n", pSPARC->ion_T); + fprintf(mdout,":TELST(K): %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(mdout,":TIOST(K): %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(mdout,":PREST(Gpa): %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(mdout,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(mdout,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(mdout,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(mdout,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(mdout,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 20)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56 + 20)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52 + 20)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 22) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + else if (strcmpi(str,":V(Bohr/atu):") == 0) + for(atm = 0; atm < pSPARC->n_atom; atm++) + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TELST(K):") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_elec_T); fscanf(rst_fp,"%lf", &pSPARC->std_elec_T); + }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); + }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); + }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); + }else if (strcmpi(str,":KENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_KE); fscanf(rst_fp,"%lf", &pSPARC->std_KE); + }else if (strcmpi(str,":FENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_PE); fscanf(rst_fp,"%lf", &pSPARC->std_PE); + }else if (strcmpi(str,":UENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_U); fscanf(rst_fp,"%lf", &pSPARC->std_U); + }else if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_Entropy); fscanf(rst_fp,"%lf", &pSPARC->std_Entropy); + } + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_TE_ext); fscanf(rst_fp,"%lf", &pSPARC->std_TE_ext); + } + } + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (strcmpi(str,":NPT_NP_QMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); + else if (strcmpi(str,":NPT_NP_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); + else if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[0]); + else if (strcmpi(str,":NPT_NP_SNOSE[1]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[1]); + else if (strcmpi(str,":NPT_NP_SNOSE[2]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[2]); + else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (strcmpi(str,":NPH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPH_bmass); + else if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); + } + else if (strcmpi(str,":LATTICE_AVG_VELOCITY:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[0]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[1]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[2]); + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[3]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[4]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[5]); + fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[6]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[7]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[8]); + + } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); + for (int i = 0; i < 3; i++){pSPARC->initialLatVecAngles[i] = cos(M_PI / 180 * pSPARC->initialLatVecAngles[i]);} + } else if (strcmpi(str,":CELL:") == 0) { + fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); + } else if (strcmpi(str,":LatUVec:") == 0) { + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); + } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->range_x = pSPARC->initialLatVecLength[0]*pSPARC->latvec_scale_x; + pSPARC->range_y = pSPARC->initialLatVecLength[1]*pSPARC->latvec_scale_y; + pSPARC->range_z = pSPARC->initialLatVecLength[2]*pSPARC->latvec_scale_z; + } else if (strcmpi(str,":LatVec:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); + fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); + fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); + } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[6]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[7]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[8]); + } else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":EXTERNAL_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->pressure_external); + else if (strcmpi(str,":EXTERNAL_STRESS:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->stress_external[0]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[1]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[2]); + fscanf(rst_fp,"%lf", &pSPARC->stress_external[3]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[4]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[5]); + } + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->mean_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Pack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + MPI_Pack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if (pSPARC->Flag_latvec_scale == 0){ + MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if (pSPARC->Flag_latvec_scale == 1){ + MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[0], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[1], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[2], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPH_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if (pSPARC->Flag_latvec_scale == 0){ + MPI_Unpack(buff, l_buff, &position, pSPARC->LatUVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if (pSPARC->Flag_latvec_scale == 1){ + MPI_Unpack(buff, l_buff, &position, pSPARC->LatVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); + } + MPI_Unpack(buff, l_buff, &position, pSPARC->rotation_matrix, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->pressure_external, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->stress_external, 6, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} + + diff --git a/src/MD_printing_refined_fractional.c b/src/MD_printing_refined_fractional.c index f29f7dfd..b38b3f9a 100644 --- a/src/MD_printing_refined_fractional.c +++ b/src/MD_printing_refined_fractional.c @@ -2995,10 +2995,10 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { } // Compute Ionic stress/pressure - if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + //if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) Calculate_ionic_stress(pSPARC); - } + //} // Calculate_stress(pSPARC); #ifdef DEBUG diff --git a/src/md.c b/src/md.c index b4360007..46293f75 100644 --- a/src/md.c +++ b/src/md.c @@ -203,6 +203,10 @@ void main_MD(SPARC_OBJ *pSPARC) { fclose(pSPARC->fp_energy); pSPARC->fp_energy = NULL; } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ + free(pSPARC->ion_vel_fractional); + free(pSPARC->Pm_ion); + } } /** @@ -360,8 +364,10 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); fflush(pSPARC->fp_energy); } + pSPARC->KE_save = 0.0; fetch_MD_cell_ingredients(pSPARC, false); + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -390,7 +396,17 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->thermos_Ti = pSPARC->ion_T; pSPARC->thermos_T = pSPARC->thermos_Ti; - + + pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); + exit(EXIT_FAILURE); + } + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); + exit(EXIT_FAILURE); + } } else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart int rank; @@ -426,10 +442,21 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->SNOSE[1] = 0.0; pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; } - - //pSPARC->thermos_Ti = pSPARC->elec_T; + // pSPARC->thermos_Ti = pSPARC->elec_T; pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + //Calculate_ionic_stress(pSPARC); + + pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); + exit(EXIT_FAILURE); + } + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); + exit(EXIT_FAILURE); + } } if(pSPARC->RestartFlag == 0){ @@ -1392,9 +1419,9 @@ Physical Review B 55.14 (1997): 8733. void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - + //Calculate initial hamitonian if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { NPT_NP_and_NPH_init_hamiltonian(pSPARC); @@ -1434,6 +1461,119 @@ void transpose_and_add(double *matrix1){ matrix1[5] = matrix1[7] = s12; } +void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + int i, j, k; + + double TEMP_TOL = 1e-12; + // Construct LatUVec; + double mag; + for(i = 0; i < 3; i++){ + mag = sqrt(pow(pSPARC->full_lattice[3 * i], 2.0) + + pow(pSPARC->full_lattice[3 * i + 1], 2.0) + + pow(pSPARC->full_lattice[3 * i + 2], 2.0)); + pSPARC->LatUVec[3 * i] = pSPARC->full_lattice[3 * i]/mag; + pSPARC->LatUVec[3 * i + 1] = pSPARC->full_lattice[3 * i + 1]/mag; + pSPARC->LatUVec[3 * i + 2] = pSPARC->full_lattice[3 * i + 2]/mag; + } + + // determinant of 3x3 Jacobian + pSPARC->Jacbdet = 0.0; + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + if(i != j && j != k && k != i) + pSPARC->Jacbdet += ((i - j) * (j - k) * (k - i)/2) * pSPARC->LatUVec[3 * i] * pSPARC->LatUVec[3 * j + 1] * pSPARC->LatUVec[3 * k + 2]; + } + } + } + + if(pSPARC->Jacbdet <= 0){ + if(rank == 0) + printf("ERROR: Volume(det(jacobian)) %lf is <= 0\n", pSPARC->Jacbdet); + exit(EXIT_FAILURE); + } + + // transformation matrix for distance + for(i = 0; i < 9; i++) + pSPARC->metricT[i] = 0.0; + + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + pSPARC->metricT[3*i + j] += pSPARC->LatUVec[3*i + k] * pSPARC->LatUVec[3*j + k]; + } + } + } + + pSPARC->metricT[1] = 2 * pSPARC->metricT[1]; + pSPARC->metricT[2] = 2 * pSPARC->metricT[2]; + pSPARC->metricT[5] = 2 * pSPARC->metricT[5]; + + // transformation matrix for gradient + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + pSPARC->gradT[3*j + i] = (pSPARC->LatUVec[3 * ((j+1) % 3) + (i+1) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+2) % 3] - pSPARC->LatUVec[3 * ((j+1) % 3) + (i+2) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+1) % 3])/pSPARC->Jacbdet; + } + } + + // transformation matrix for laplacian + for(i = 0; i < 9; i++) + pSPARC->lapcT[i] = 0.0; + + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + pSPARC->lapcT[3*i + j] += pSPARC->gradT[3*i + k] * pSPARC->gradT[3*j + k]; + } + } + } + + /* Different cell types for laplacian */ + if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 11; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 12; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 13; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 14; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 15; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 16; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 17; +#ifdef DEBUG + if(!rank) + printf("\n\nCELL_TYP: %d\n\n",pSPARC->cell_typ); +#endif + /* transform the coefficiens of lapacian*/ + // int p, FDn = pSPARC->order/2; + // double dx_inv, dy_inv, dz_inv, dx2_inv, dy2_inv, dz2_inv; + // dx_inv = 1.0 / (pSPARC->delta_x); + // dy_inv = 1.0 / (pSPARC->delta_y); + // dz_inv = 1.0 / (pSPARC->delta_z); + // dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + // dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + // dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + // for (p = 0; p < FDn + 1; p++) { + // pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + // pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + // pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + // pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + // pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + // pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + // pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + // pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + // pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + // pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + // pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + // pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + // } + // TODO: Find maximum eigenvalue of Hamiltionian (= max. eigvalue of -0.5 lap) for non orthogonal periodic systems +} /* Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix @@ -1458,17 +1598,8 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ //Compute metric_tensor (G) in real-space (not reciprocal space) cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - - // This is needed since, they will be used in function 'Cart2nonCart_transformMat' to update various quantities - for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles - pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; - } - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); + Cart2nonCart_transformMat_MD(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) @@ -1562,20 +1693,8 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - //Update LATVEC_SCALE and LatVec - for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles - pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; - } - if (pSPARC->Flag_latvec_scale == 1){ // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - } - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); + Cart2nonCart_transformMat_MD(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) @@ -1587,6 +1706,22 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + } //Update reciprocal lattice vectors, reciprocal metric tensor for (int i = 0; i < 9; i++){ @@ -1615,7 +1750,7 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell = old_cell@rotation_matrix; + //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell@Rotation_matrix.T = old_cell; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); //Initiating cell lattice vectors velocity as zero @@ -1662,7 +1797,27 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } -void Calculate_Kinetic_energy_and_Kinetic_stress(SPARC_OBJ *pSPARC){ +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double vector[3]={0.0}; + pSPARC->KE = 0.0; + + int count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, &pSPARC->Pm_ion[count*3], 1, 0.0, vector, 1); + pSPARC->KE += cblas_ddot(3, vector, 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + count++; + } + } + + pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -1673,26 +1828,21 @@ void Calculate_Kinetic_energy_and_Kinetic_stress(SPARC_OBJ *pSPARC){ int count = 0; for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+2] * pSPARC->ion_vel[count*3+2]; + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+2] * pSPARC->ion_vel_fractional[count*3+2]; count++; } } + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - pSPARC->KE = pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[4] + pSPARC->kinetic_stress[8]; - - //Convert kinetic stress to fractional coordinates - double temp_mat1[9]; - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat1, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat1, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); } @@ -1717,10 +1867,19 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // // Calculate kinetic energy and kinetic stress of ions + // Calculating kinetic energy of ions cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); - Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->metric_tensor, 3, 0.0, pSPARC->Pm_ion, 3); + int count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + cblas_dscal(3 * pSPARC->nAtomv[ityp], pSPARC->Mass[ityp], &pSPARC->Pm_ion[count], 1); + count = count + 3 * pSPARC->nAtomv[ityp]; + } + // Calculate kinetic energy and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + pSPARC->KE_save = pSPARC->KE; // Calculating thermostat energies pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper @@ -1732,7 +1891,8 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ transpose_and_add(pSPARC->Pm_metric_tensor); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3 * baro_const2, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; @@ -1780,14 +1940,14 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); double ktemp = pSPARC->kB * pSPARC->thermos_T; - unsigned int count; + int count; //Initialize empty temporary matrices and vectors double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; double internal_stress_cartesian[9]; //Initialize some useful constants - double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3] = {0}; + double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]={0}; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; @@ -1803,20 +1963,24 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } double baro_const3 = 1.0 / baro_const1; - double thermo_const0 = 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0]; - + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// + + //Calculate_Ionic_particles_Kinetic_energy(pSPARC); + pSPARC->KE = pSPARC->KE_save; + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double factor; + double Sa = 0.0; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) if (pSPARC->NPT_NP_qmass > 0){ pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; - pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; + Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; + pSPARC->SNOSE[1] += 0.5 * Sa * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; #ifdef DEBUG if (rank == 0) { - printf("factor Eqn.18G is %12.9f\n", factor); + printf("Sa is %12.9f\n", Sa); printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); } #endif @@ -1881,7 +2045,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } - + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) @@ -1896,21 +2060,26 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds to Eqn. 18i in Hernandez paper - cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - cblas_dcopy(3 * pSPARC->n_atom, pSPARC->forces, 1, pSPARC->ion_accel, 1); //copy the ion forces array into ion acceleration array + double *ion_forces_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); + exit(EXIT_FAILURE); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->forces, 3, pSPARC->full_lattice, 3, 0.0, ion_forces_fractional, 3); + // Eqn. 18i: momentum += 0.5 * dt * S * D2C + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); count = 0; - unsigned int len; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - len = 3 * pSPARC->nAtomv[ityp]; - cblas_dscal(len, 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_accel[count], 1); // Scale by 1/mass - count += len; + cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); + count = count + 3 * pSPARC->nAtomv[ityp]; } - // Eqn. 18i: momentum += 0.5 * dt * S * D2C (but updating velocity in cartesian coordinates instead of momentum) - cblas_daxpy(3 * pSPARC->n_atom, thermo_const0, pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); - //Update the kinetic energy and kinetic stress of the Ionic particles - Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); - - //Calculate internal pressure + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + for (int i = 0; i < 9; i++){ pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - pSPARC->internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); } @@ -1959,7 +2128,8 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, -2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress - cblas_dscal(3 * pSPARC->n_atom, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel, 1); + // Obtain updated velocities in cartesian coordinates for use in MD_QOI function + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); int check1 = (pSPARC->PrintMDout == 1 && !rank); MD_QOI(pSPARC, avgvel, maxvel, mindis); Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file @@ -1972,12 +2142,20 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper (but updating velocity in cartesian coordinates instead of momentum; they are equivalent formulation as kinetic energy and kinetic stress is consistent with this change) - // Eqn. 18a: momentum += 0.5 * dt * S * D2C - cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - cblas_daxpy(3 * pSPARC->n_atom, thermo_const0, pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); + // This setup corresponds to Eqn. 18a in Hernandez paper + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); + free(ion_forces_fractional); + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); + count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); + count = count + 3 * pSPARC->nAtomv[ityp]; + } // Calculate internal pressure and kinetic stress - Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); // Now we update/Step-up the momenta of the barostat by dt/2 @@ -1997,20 +2175,25 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } + + // Now we update/Step-up the momenta of the thermostat by dt/2 // This setup corresponds to Eqn. 18c in the Hernandez paper // Skip this step if doing NPH ensemble if (pSPARC->NPT_NP_qmass > 0){ + double factor; factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + #ifdef DEBUG if (rank == 0) - printf("factor Eqn.18c is %12.9f\n", factor); + printf("factor is %12.9f\n", factor); #endif if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ if (rank == 0) printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); } + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); #ifdef DEBUG if (rank == 0) @@ -2060,33 +2243,32 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma //Eqn. 18e is implicitly solved in the below subroutine Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new, NPT_NPH_ANGLES, NPT_NPHconstraintFlag); - //Before updating cell parameters, store the old reciprocal lattice - for (int i = 0; i < 9; i++) { temp_mat[i] = pSPARC->reciprocal_lattice[i];} + //Before updating cell parameters, convert cartesian atomic position coordinates to fractional + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, pSPARC->reciprocal_lattice, 3, 0.0, atom_pos_fractional, 3); + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor fetch_MD_cell_ingredients(pSPARC, true); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, temp_mat_b, 3); - // Now reconvert atomic positions to cartesian coordinates, accounting change in cell size/shape (remember this are still of previous step, they have yet to be updated) - double *atom_pos_update = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); //temporary array - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, temp_mat_b, 3, 0.0, atom_pos_update, 3); - cblas_dcopy(3 * pSPARC->n_atom, atom_pos_update, 1, pSPARC->atom_pos, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, temp_mat_b, 3, 0.0, atom_pos_update, 3); - cblas_dcopy(3 * pSPARC->n_atom, atom_pos_update, 1, pSPARC->ion_vel, 1); - free(atom_pos_update); - - //Update Atomic position in cartesian coordinates coordinates (Eqn. 18f in Hernandez paper) - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel, 1, pSPARC->atom_pos, 1); - //Update atomic positions and restore ionic velocities - cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); - //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + //Update Atomic position in fractional coordinates (Eqn. 18f in Hernandez paper) + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel_fractional, 1, atom_pos_fractional, 1); + + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, atom_pos_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->atom_pos, 3); + free(atom_pos_fractional); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + + //Update atomic positions and restore ionic velocities + cblas_dscal(3 * pSPARC->n_atom, 1 / S_new, pSPARC->ion_vel, 1); //Update kinetic energy and kinetic stress based on new S pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); + pSPARC->KE_save = pSPARC->KE; for (int i = 0; i < 9; i++){ pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); } @@ -2126,6 +2308,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper } + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); @@ -2156,7 +2339,8 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int gpig[0] = 0; gpig[4] = 0; } - + + constraint_velocity[0] = gpig[0] * baro_const4; constraint_velocity[4] = gpig[4] * baro_const4; constraint_velocity[8] = gpig[8] * baro_const4; @@ -2258,7 +2442,6 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } } - if (NPT_NPH_ANGLES == 0){ if (NPT_NPHconstraintFlag == 4){ new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; @@ -2299,6 +2482,7 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } } #endif + } @@ -2549,6 +2733,7 @@ void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { } + /* @ brief: function to write all relevant DFT quantities generated during MD simulation */ @@ -2592,9 +2777,11 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); - else + fprintf(output_md,":Desc_SNOSE[0]: Position variable of the thermostat\n"); + fprintf(output_md,":Desc_SNOSE[1]: Velocity variable of the thermostat\n"); + } else fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha \n"); } if(pSPARC->Calc_stress == 1){ @@ -2641,9 +2828,11 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); - if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":SNOSE[0]:%18.10E \n", pSPARC->SNOSE[0]); + fprintf(output_md,":SNOSE[1]:%18.10E \n", pSPARC->SNOSE[1]); + } if(strcmpi(pSPARC->MDMeth,"NPH") == 0) fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); // Print atomic position @@ -3538,6 +3727,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } + /* @ brief: function to rename the restart file */ From 713d637cfdbabaa3db11e3b8fd9d5542f96eca38 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Thu, 2 Apr 2026 16:28:16 -0400 Subject: [PATCH 45/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/MD_printing_refined_cartesian.c | 66 ++++++++------- src/MD_printing_refined_fractional.c | 91 ++++++++++----------- src/include/isddft.h | 2 + src/md.c | 117 ++++++++++++++++----------- 4 files changed, 154 insertions(+), 122 deletions(-) diff --git a/src/MD_printing_refined_cartesian.c b/src/MD_printing_refined_cartesian.c index f34b3880..2218351c 100644 --- a/src/MD_printing_refined_cartesian.c +++ b/src/MD_printing_refined_cartesian.c @@ -316,9 +316,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); } else{ pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; @@ -360,6 +360,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); fflush(pSPARC->fp_energy); } + pSPARC->KE_save = 0.0; fetch_MD_cell_ingredients(pSPARC, false); pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -399,9 +400,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { //pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; //This is computed in function: 'fetch_MD_cell_ingredients_restart' below if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); } else{ pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; @@ -1396,7 +1397,7 @@ void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double * MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + if ((pSPARC->MDCount == 1)) { NPT_NP_and_NPH_init_hamiltonian(pSPARC); } //NPT_NPH_main routine @@ -1718,9 +1719,9 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// // // Calculate kinetic energy and kinetic stress of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); + cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - cblas_dscal(pSPARC->n_atom * 3, 1.0 / pSPARC->SNOSE[2], pSPARC->ion_vel, 1); + cblas_dscal(3 * pSPARC->n_atom, 1.0 / pSPARC->SNOSE[2], pSPARC->ion_vel, 1); pSPARC->KE_save = pSPARC->KE; // Calculating thermostat energies pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper @@ -1780,14 +1781,14 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); double ktemp = pSPARC->kB * pSPARC->thermos_T; - unsigned int count; + int count; //Initialize empty temporary matrices and vectors double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; double internal_stress_cartesian[9]; //Initialize some useful constants - double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3] = {0}; + double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]={0}; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; @@ -1803,9 +1804,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } double baro_const3 = 1.0 / baro_const1; - double thermo_const0 = 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0]; + + + //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// pSPARC->KE = pSPARC->KE_save; + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// double factor; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) @@ -1881,7 +1885,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } - + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) @@ -1906,7 +1910,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma count += len; } // Eqn. 18i: momentum += 0.5 * dt * S * D2C (but updating velocity in cartesian coordinates instead of momentum) - cblas_daxpy(3 * pSPARC->n_atom, thermo_const0, pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); //Update the kinetic energy and kinetic stress of the Ionic particles Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); @@ -1920,15 +1924,15 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma //Update Hamiltonian double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; - } + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; + // } pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper } else { - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPH = sumAllHamilTerms ; - } + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; + // } pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } #ifdef DEBUG @@ -1976,7 +1980,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // This setup corresponds to Eqn. 18a in Hernandez paper (but updating velocity in cartesian coordinates instead of momentum; they are equivalent formulation as kinetic energy and kinetic stress is consistent with this change) // Eqn. 18a: momentum += 0.5 * dt * S * D2C cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - cblas_daxpy(3 * pSPARC->n_atom, thermo_const0, pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); // Calculate internal pressure and kinetic stress Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); @@ -1998,20 +2002,25 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } + + // Now we update/Step-up the momenta of the thermostat by dt/2 // This setup corresponds to Eqn. 18c in the Hernandez paper // Skip this step if doing NPH ensemble if (pSPARC->NPT_NP_qmass > 0){ + double factor; factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + #ifdef DEBUG if (rank == 0) - printf("factor Eqn.18c is %12.9f\n", factor); + printf("factor is %12.9f\n", factor); #endif if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ if (rank == 0) printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); } + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); #ifdef DEBUG if (rank == 0) @@ -2073,7 +2082,6 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, temp_mat_b, 3, 0.0, atom_pos_update, 3); cblas_dcopy(3 * pSPARC->n_atom, atom_pos_update, 1, pSPARC->ion_vel, 1); free(atom_pos_update); - //Update Atomic position in cartesian coordinates coordinates (Eqn. 18f in Hernandez paper) cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel, 1, pSPARC->atom_pos, 1); //Update atomic positions and restore ionic velocities @@ -2085,13 +2093,13 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - //Update kinetic energy and kinetic stress based on new S pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); + pSPARC->KE_save = pSPARC->KE; for (int i = 0; i < 9; i++){ pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); } - pSPARC->KE_save = pSPARC->KE; + // Update SNOSE[0] to S_new if (pSPARC->NPT_NP_qmass > 0){ pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; @@ -2127,6 +2135,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper } + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); @@ -2157,7 +2166,8 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int gpig[0] = 0; gpig[4] = 0; } - + + constraint_velocity[0] = gpig[0] * baro_const4; constraint_velocity[4] = gpig[4] * baro_const4; constraint_velocity[8] = gpig[8] * baro_const4; @@ -2259,7 +2269,6 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } } - if (NPT_NPH_ANGLES == 0){ if (NPT_NPHconstraintFlag == 4){ new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; @@ -2300,6 +2309,7 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } } #endif + } @@ -2395,6 +2405,7 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ } + /** * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c */ @@ -3217,6 +3228,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); + pSPARC->mean_internal_pressure /= CONST_HA_BOHR; pSPARC->std_internal_pressure /= CONST_HA_BOHR; }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); }else if (strcmpi(str,":KENST:") == 0 && pSPARC->RestartFlag == 1){ diff --git a/src/MD_printing_refined_fractional.c b/src/MD_printing_refined_fractional.c index b38b3f9a..03b3a0c9 100644 --- a/src/MD_printing_refined_fractional.c +++ b/src/MD_printing_refined_fractional.c @@ -320,9 +320,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); } else{ pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; @@ -415,9 +415,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { //pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; //This is computed in function: 'fetch_MD_cell_ingredients_restart' below if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); } else{ pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; @@ -445,7 +445,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { // pSPARC->thermos_Ti = pSPARC->elec_T; pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - Calculate_ionic_stress(pSPARC); + //Calculate_ionic_stress(pSPARC); pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); if (pSPARC->ion_vel_fractional == NULL) { @@ -1423,7 +1423,7 @@ void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double * MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + if ((pSPARC->MDCount == 1)) { NPT_NP_and_NPH_init_hamiltonian(pSPARC); } //NPT_NPH_main routine @@ -1768,10 +1768,10 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->SNOSE[0] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); } else { - cblas_dscal(9, pSPARC->SNOSE[0] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); @@ -1891,8 +1891,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ transpose_and_add(pSPARC->Pm_metric_tensor); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3 * baro_const2, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; @@ -1947,11 +1946,10 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma double internal_stress_cartesian[9]; //Initialize some useful constants - double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]; + double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]={0}; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; - NPT_NPHscaleVecs[3] = {0}; NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper @@ -1959,7 +1957,6 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma else{ NPT_NPH_ANGLES = pSPARC->NPH_ANGLES; NPT_NPHconstraintFlag = pSPARC->NPHconstraintFlag; - NPT_NPHscaleVecs[3] = {0}; NPT_NPHscaleVecs[0] = pSPARC->NPHscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPHscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPHscaleVecs[2]; baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper @@ -1969,20 +1966,19 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - //Calculate_Ionic_particles_Kinetic_energy(pSPARC); pSPARC->KE = pSPARC->KE_save; // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; + double factor; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) if (pSPARC->NPT_NP_qmass > 0){ pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; - pSPARC->SNOSE[1] += 0.5 * Sa * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; + factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; + pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; #ifdef DEBUG if (rank == 0) { - printf("Sa is %12.9f\n", Sa); + printf("factor Eqn.18G is %12.9f\n", factor); printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); } #endif @@ -1995,9 +1991,9 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3] - pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5] - pSPARC->stress_i[5]; - internal_stress_cartesian[1] = pSPARC->stress[1] - pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1] - pSPARC->stress_i[1]; - internal_stress_cartesian[5] = pSPARC->stress[4] - pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4] - pSPARC->stress_i[4]; + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat_b, 3); cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, pSPARC->reciprocal_lattice, 3, temp_mat_b, 3, 0.0, pSPARC->internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 @@ -2019,12 +2015,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHscaleVecs); + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); } } else { if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHscaleVecs); + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); } } @@ -2063,9 +2059,9 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds to Eqn. 18i in Hernandez paper double *ion_forces_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); - exit(EXIT_FAILURE); + if (ion_forces_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); + exit(EXIT_FAILURE); } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->forces, 3, pSPARC->full_lattice, 3, 0.0, ion_forces_fractional, 3); // Eqn. 18i: momentum += 0.5 * dt * S * D2C @@ -2077,7 +2073,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma count = 0; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); - count = count + 3 * pSPARC->nAtomv[ityp]; + count += 3 * pSPARC->nAtomv[ityp]; } // Calculate internal pressure and kinetic stress Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); @@ -2131,7 +2127,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, -2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress // Obtain updated velocities in cartesian coordinates for use in MD_QOI function - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); int check1 = (pSPARC->PrintMDout == 1 && !rank); MD_QOI(pSPARC, avgvel, maxvel, mindis); Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file @@ -2248,26 +2244,23 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma //Before updating cell parameters, convert cartesian atomic position coordinates to fractional double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, pSPARC->reciprocal_lattice, 3, 0.0, atom_pos_fractional, 3); - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor fetch_MD_cell_ingredients(pSPARC, true); - - //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - //Update Atomic position in fractional coordinates (Eqn. 18f in Hernandez paper) cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel_fractional, 1, atom_pos_fractional, 1); - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, atom_pos_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->atom_pos, 3); free(atom_pos_fractional); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); - //Update atomic positions and restore ionic velocities - cblas_dscal(3 * pSPARC->n_atom, 1 / S_new, pSPARC->ion_vel, 1); + cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); + + //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + //Update kinetic energy and kinetic stress based on new S pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); pSPARC->KE_save = pSPARC->KE; @@ -2779,9 +2772,11 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); - else + fprintf(output_md,":Desc_SNOSE[0]: Position variable of the thermostat\n"); + fprintf(output_md,":Desc_SNOSE[1]: Velocity variable of the thermostat\n"); + } else fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha \n"); } if(pSPARC->Calc_stress == 1){ @@ -2828,9 +2823,11 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); - if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":SNOSE[0]:%18.10E \n", pSPARC->SNOSE[0]); + fprintf(output_md,":SNOSE[1]:%18.10E \n", pSPARC->SNOSE[1]); + } if(strcmpi(pSPARC->MDMeth,"NPH") == 0) fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); // Print atomic position @@ -2995,10 +2992,10 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { } // Compute Ionic stress/pressure - //if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) Calculate_ionic_stress(pSPARC); - //} + } // Calculate_stress(pSPARC); #ifdef DEBUG @@ -3398,7 +3395,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); + pSPARC->mean_internal_pressure /= CONST_HA_BOHR3_GPA; pSPARC->std_internal_pressure /= CONST_HA_BOHR3_GPA; }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); }else if (strcmpi(str,":KENST:") == 0 && pSPARC->RestartFlag == 1){ diff --git a/src/include/isddft.h b/src/include/isddft.h index 708c723b..005e8d46 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -828,6 +828,7 @@ typedef struct _SPARC_OBJ{ double mean_elec_T; // Average of electronic temperature double mean_ion_T; // Average of ionic temperature double mean_internal_pressure; // Average of the internal pressure + double mean_total_internal_stress[9]; //Average of each total internal stress component double mean_TE; // Average of total energy double mean_KE; // Average of kinetic energy of ions double mean_PE; // Average of electronic energy @@ -837,6 +838,7 @@ typedef struct _SPARC_OBJ{ double std_elec_T; // Standard deviation of electronic temperature double std_ion_T; // Standard deviation of ionic temperature double std_internal_pressure; // Standard deviation of the internal pressure + double std_total_internal_stress[9]; //Standard deviation of each total internal stress component double std_TE; // Standard deviation of total energy double std_KE; // Standard deviation of kinetic energy of ions double std_PE; // Standard deviation of electronic energy diff --git a/src/md.c b/src/md.c index 46293f75..d2e1df4c 100644 --- a/src/md.c +++ b/src/md.c @@ -100,10 +100,11 @@ void main_MD(SPARC_OBJ *pSPARC) { if(pSPARC->RestartFlag == 0){ fprintf(output_md,":MDSTEP: %d\n", 1); fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } } - fclose(output_md); } @@ -320,9 +321,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); } else{ pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; @@ -330,11 +331,11 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->maxTimeIter = 100; + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ if(pSPARC->NPT_NP_bmass == 0.0) { if (!rank) { printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); - printf("herere"); exit(EXIT_FAILURE); } } @@ -344,7 +345,6 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { if(pSPARC->NPH_bmass == 0.0) { if (!rank) { printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); - printf("he1"); exit(EXIT_FAILURE); } } @@ -352,7 +352,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { if (rank == 0) { // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies_NPH2.log", "w"); + pSPARC->fp_energy = fopen("MD_energies_NPH_redone_full_flex.log", "w"); if (pSPARC->fp_energy == NULL) { fprintf(stderr, "Error: Could not open energy log file!\n"); @@ -415,9 +415,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { //pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; //This is computed in function: 'fetch_MD_cell_ingredients_restart' below if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); } else{ pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; @@ -571,6 +571,10 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; + for (int i = 0; i < 9; i++){ + pSPARC->mean_total_internal_stress[i] = 0.0; + pSPARC->std_total_internal_stress[i] = 0.0; + } } #endif } @@ -1423,7 +1427,7 @@ void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double * MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + if ((pSPARC->MDCount == 1)) { NPT_NP_and_NPH_init_hamiltonian(pSPARC); } //NPT_NPH_main routine @@ -1768,10 +1772,10 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->SNOSE[0] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); } else { - cblas_dscal(9, pSPARC->SNOSE[0] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); @@ -1891,8 +1895,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ transpose_and_add(pSPARC->Pm_metric_tensor); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3 * baro_const2, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; @@ -1967,20 +1970,19 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - //Calculate_Ionic_particles_Kinetic_energy(pSPARC); pSPARC->KE = pSPARC->KE_save; // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; + double factor; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) if (pSPARC->NPT_NP_qmass > 0){ pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; - pSPARC->SNOSE[1] += 0.5 * Sa * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; + factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; + pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; #ifdef DEBUG if (rank == 0) { - printf("Sa is %12.9f\n", Sa); + printf("factor Eqn.18G is %12.9f\n", factor); printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); } #endif @@ -2061,9 +2063,9 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) // This setup corresponds to Eqn. 18i in Hernandez paper double *ion_forces_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); - exit(EXIT_FAILURE); + if (ion_forces_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); + exit(EXIT_FAILURE); } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->forces, 3, pSPARC->full_lattice, 3, 0.0, ion_forces_fractional, 3); // Eqn. 18i: momentum += 0.5 * dt * S * D2C @@ -2075,7 +2077,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma count = 0; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); - count = count + 3 * pSPARC->nAtomv[ityp]; + count += 3 * pSPARC->nAtomv[ityp]; } // Calculate internal pressure and kinetic stress Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); @@ -2121,15 +2123,20 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } #endif - // For printing, convert the total internal stress and the kinetic stress to cartesian coordinates - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); + // For printing, convert the total internal stress, constraint stress and the kinetic stress to cartesian coordinates + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); //Already divided by volume earlier cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->total_internal_stress, 3); //Mutliplied by 2 so as to remove the effect of previous divisions by 2 in the kinetic_stress, internal_stress_fractional cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, -2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->constraint_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->constraint_stress, 3); + + // Obtain updated velocities in cartesian coordinates for use in MD_QOI function - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); int check1 = (pSPARC->PrintMDout == 1 && !rank); MD_QOI(pSPARC, avgvel, maxvel, mindis); Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file @@ -2246,26 +2253,23 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma //Before updating cell parameters, convert cartesian atomic position coordinates to fractional double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, pSPARC->reciprocal_lattice, 3, 0.0, atom_pos_fractional, 3); - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor fetch_MD_cell_ingredients(pSPARC, true); - - //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - //Update Atomic position in fractional coordinates (Eqn. 18f in Hernandez paper) cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel_fractional, 1, atom_pos_fractional, 1); - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, atom_pos_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->atom_pos, 3); free(atom_pos_fractional); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); - //Update atomic positions and restore ionic velocities - cblas_dscal(3 * pSPARC->n_atom, 1 / S_new, pSPARC->ion_vel, 1); + cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); + + //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + //Update kinetic energy and kinetic stress based on new S pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); pSPARC->KE_save = pSPARC->KE; @@ -2896,16 +2900,20 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":STRIO:\n"); double temp_stress[6]; temp_stress[0] = pSPARC->kinetic_stress[0]; temp_stress[1] = pSPARC->kinetic_stress[1]; temp_stress[2] = pSPARC->kinetic_stress[2]; - temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[7]; + temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[8]; PrintStress (pSPARC, temp_stress, output_md); //Print kinetic stress as defined in the (E. Hernandez, 2001) paper fprintf(output_md,":STRESS:\n"); double stress_e[6]; // electronic stress for (int i = 0; i < 6; i++) stress_e[i] = pSPARC->stress[i]; // stress_i or ionic stress function is never called in NPT_NP or NPH ensemble, so pSPARC->stress does not include contribution from it, and thus no need to subtract stress_i from pSPARC->stress, as done in other ensembles PrintStress (pSPARC, stress_e, output_md); + fprintf(output_md,":CONSTRESS:\n"); + temp_stress[0] = pSPARC->constraint_stress[0]; temp_stress[1] = pSPARC->constraint_stress[1]; temp_stress[2] = pSPARC->constraint_stress[2]; + temp_stress[3] = pSPARC->constraint_stress[4]; temp_stress[4] = pSPARC->constraint_stress[5]; temp_stress[5] = pSPARC->constraint_stress[8]; + PrintStress (pSPARC, temp_stress, output_md); fprintf(output_md,":TOTSTRESS:\n"); //Print total internal stress accouting for the constraints in NPT_NP or NPH ensemble temp_stress[0] = pSPARC->total_internal_stress[0]; temp_stress[1] = pSPARC->total_internal_stress[1]; temp_stress[2] = pSPARC->total_internal_stress[2]; - temp_stress[3] = pSPARC->total_internal_stress[4]; temp_stress[4] = pSPARC->total_internal_stress[5]; temp_stress[5] = pSPARC->total_internal_stress[7]; + temp_stress[3] = pSPARC->total_internal_stress[4]; temp_stress[4] = pSPARC->total_internal_stress[5]; temp_stress[5] = pSPARC->total_internal_stress[8]; PrintStress (pSPARC, temp_stress, output_md); } } @@ -2928,10 +2936,12 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i) * CONST_HA_BOHR3_GPA); } else{ //Trigger NPT_NP or NPH ensemble stress printing - double ion_kinetic_pressure; - ion_kinetic_pressure = -1.0 / 3.0 * (pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[1] + pSPARC->kinetic_stress[2]); //Kinetic stress is already multiplied by 2 + double ion_kinetic_pressure, constraint_pressure; + ion_kinetic_pressure = 1.0 / 3.0 * (pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[4] + pSPARC->kinetic_stress[8]); //Kinetic stress is already multiplied by 2 + constraint_pressure = 1.0 / 3.0 * (pSPARC->constraint_stress[0] + pSPARC->constraint_stress[4] + pSPARC->constraint_stress[8]); //Constraint stress is already multiplied by 2 fprintf(output_md,":PRESIO: %18.10E\n", ion_kinetic_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->internal_pressure - ion_kinetic_pressure) * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->internal_pressure - ion_kinetic_pressure + constraint_pressure) * CONST_HA_BOHR3_GPA); + fprintf(output_md,":CONPRES: %18.10E\n", constraint_pressure * CONST_HA_BOHR3_GPA); fprintf(output_md,":TOTPRES: %18.10E\n", pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); //Also accounts for pressure due to constraint stress } @@ -2944,6 +2954,14 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); fprintf(output_md,":PREST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":MEAN_TOTSTRESS:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->mean_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[2] * CONST_HA_BOHR3_GPA + , pSPARC->mean_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[5] * CONST_HA_BOHR3_GPA + , pSPARC->mean_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[8] * CONST_HA_BOHR3_GPA); + fprintf(output_md,":STD_TOTSTRESS:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->std_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[2] * CONST_HA_BOHR3_GPA + , pSPARC->std_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[5] * CONST_HA_BOHR3_GPA + , pSPARC->std_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[8] * CONST_HA_BOHR3_GPA); fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); @@ -3001,11 +3019,11 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) Calculate_ionic_stress(pSPARC); } - + // Calculate_stress(pSPARC); #ifdef DEBUG // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old; + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old, mean_total_internal_stress_old[9]; int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; mean_Te_old = pSPARC->mean_elec_T; mean_Ti_old = pSPARC->mean_ion_T; @@ -3015,9 +3033,11 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { mean_U_old = pSPARC->mean_U; mean_Eent_old = pSPARC->mean_Entropy; mean_internal_pressure_old = pSPARC->mean_internal_pressure; + for (int i = 0; i < 9; i++){mean_total_internal_stress_old[i] = pSPARC->mean_total_internal_stress[i];} pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; + for (int i = 0; i < 9; i++){pSPARC->mean_total_internal_stress[i] = (mean_total_internal_stress_old[i] * (Count - 1) + pSPARC->total_internal_stress[i]) / Count;} pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; @@ -3026,6 +3046,7 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); pSPARC->std_internal_pressure = sqrt(fabs( ((pow(pSPARC->std_internal_pressure,2.0) + pow(mean_internal_pressure_old,2.0)) * (Count - 1) + pow(pSPARC->internal_pressure,2.0))/Count - pow(pSPARC->mean_internal_pressure,2.0) )); + for (int i = 0; i < 9; i++){pSPARC->std_total_internal_stress[i] = sqrt(fabs( ((pow(pSPARC->std_total_internal_stress[i],2.0) + pow(mean_total_internal_stress_old[i],2.0)) * (Count - 1) + pow(pSPARC->total_internal_stress[i],2.0))/Count - pow(pSPARC->mean_total_internal_stress[i],2.0) ));} pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); @@ -3400,7 +3421,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); + pSPARC->mean_internal_pressure /= CONST_HA_BOHR3_GPA; pSPARC->std_internal_pressure /= CONST_HA_BOHR3_GPA; }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); }else if (strcmpi(str,":KENST:") == 0 && pSPARC->RestartFlag == 1){ From a81d05cad92c1e195d879a4e1c7b45216f6e795b Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Thu, 2 Apr 2026 20:03:07 -0400 Subject: [PATCH 46/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/MD_printing_refined_fractional.c | 114 +++++--- src/md.c | 394 +++++++++++---------------- 2 files changed, 247 insertions(+), 261 deletions(-) diff --git a/src/MD_printing_refined_fractional.c b/src/MD_printing_refined_fractional.c index 03b3a0c9..5c51933a 100644 --- a/src/MD_printing_refined_fractional.c +++ b/src/MD_printing_refined_fractional.c @@ -2765,9 +2765,10 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + fprintf(output_md,":Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 \n"); if (pSPARC->Flag_latvec_scale == 0){ fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = 1 \n",pSPARC->MDMeth); } else { fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); @@ -2858,6 +2859,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ fprintf(output_md,":ANGLES:\n"); fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(output_md,":VOLUME: %18.10E\n", pSPARC->volumeCell); if (pSPARC->Flag_latvec_scale == 0){ fprintf(output_md,":CELL:\n"); fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); @@ -2891,16 +2893,20 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":STRIO:\n"); double temp_stress[6]; temp_stress[0] = pSPARC->kinetic_stress[0]; temp_stress[1] = pSPARC->kinetic_stress[1]; temp_stress[2] = pSPARC->kinetic_stress[2]; - temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[7]; + temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[8]; PrintStress (pSPARC, temp_stress, output_md); //Print kinetic stress as defined in the (E. Hernandez, 2001) paper fprintf(output_md,":STRESS:\n"); double stress_e[6]; // electronic stress for (int i = 0; i < 6; i++) stress_e[i] = pSPARC->stress[i]; // stress_i or ionic stress function is never called in NPT_NP or NPH ensemble, so pSPARC->stress does not include contribution from it, and thus no need to subtract stress_i from pSPARC->stress, as done in other ensembles PrintStress (pSPARC, stress_e, output_md); + fprintf(output_md,":CONSTRESS:\n"); + temp_stress[0] = pSPARC->constraint_stress[0]; temp_stress[1] = pSPARC->constraint_stress[1]; temp_stress[2] = pSPARC->constraint_stress[2]; + temp_stress[3] = pSPARC->constraint_stress[4]; temp_stress[4] = pSPARC->constraint_stress[5]; temp_stress[5] = pSPARC->constraint_stress[8]; + PrintStress (pSPARC, temp_stress, output_md); fprintf(output_md,":TOTSTRESS:\n"); //Print total internal stress accouting for the constraints in NPT_NP or NPH ensemble temp_stress[0] = pSPARC->total_internal_stress[0]; temp_stress[1] = pSPARC->total_internal_stress[1]; temp_stress[2] = pSPARC->total_internal_stress[2]; - temp_stress[3] = pSPARC->total_internal_stress[4]; temp_stress[4] = pSPARC->total_internal_stress[5]; temp_stress[5] = pSPARC->total_internal_stress[7]; + temp_stress[3] = pSPARC->total_internal_stress[4]; temp_stress[4] = pSPARC->total_internal_stress[5]; temp_stress[5] = pSPARC->total_internal_stress[8]; PrintStress (pSPARC, temp_stress, output_md); } } @@ -2923,10 +2929,12 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i) * CONST_HA_BOHR3_GPA); } else{ //Trigger NPT_NP or NPH ensemble stress printing - double ion_kinetic_pressure; - ion_kinetic_pressure = -1.0 / 3.0 * (pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[1] + pSPARC->kinetic_stress[2]); //Kinetic stress is already multiplied by 2 + double ion_kinetic_pressure, constraint_pressure; + ion_kinetic_pressure = 1.0 / 3.0 * (pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[4] + pSPARC->kinetic_stress[8]); //Kinetic stress is already multiplied by 2 + constraint_pressure = 1.0 / 3.0 * (pSPARC->constraint_stress[0] + pSPARC->constraint_stress[4] + pSPARC->constraint_stress[8]); //Constraint stress is already multiplied by 2 fprintf(output_md,":PRESIO: %18.10E\n", ion_kinetic_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->internal_pressure - ion_kinetic_pressure) * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->internal_pressure - ion_kinetic_pressure + constraint_pressure) * CONST_HA_BOHR3_GPA); + fprintf(output_md,":CONPRES: %18.10E\n", constraint_pressure * CONST_HA_BOHR3_GPA); fprintf(output_md,":TOTPRES: %18.10E\n", pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); //Also accounts for pressure due to constraint stress } @@ -2939,6 +2947,14 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); fprintf(output_md,":PREST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":MEAN_TOTSTRESS:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->mean_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[2] * CONST_HA_BOHR3_GPA + , pSPARC->mean_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[5] * CONST_HA_BOHR3_GPA + , pSPARC->mean_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[8] * CONST_HA_BOHR3_GPA); + fprintf(output_md,":STD_TOTSTRESS:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->std_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[2] * CONST_HA_BOHR3_GPA + , pSPARC->std_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[5] * CONST_HA_BOHR3_GPA + , pSPARC->std_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[8] * CONST_HA_BOHR3_GPA); fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); @@ -2996,11 +3012,11 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) Calculate_ionic_stress(pSPARC); } - + // Calculate_stress(pSPARC); #ifdef DEBUG // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old; + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old, mean_total_internal_stress_old[9]; int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; mean_Te_old = pSPARC->mean_elec_T; mean_Ti_old = pSPARC->mean_ion_T; @@ -3010,9 +3026,11 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { mean_U_old = pSPARC->mean_U; mean_Eent_old = pSPARC->mean_Entropy; mean_internal_pressure_old = pSPARC->mean_internal_pressure; + for (int i = 0; i < 9; i++){mean_total_internal_stress_old[i] = pSPARC->mean_total_internal_stress[i];} pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; + for (int i = 0; i < 9; i++){pSPARC->mean_total_internal_stress[i] = (mean_total_internal_stress_old[i] * (Count - 1) + pSPARC->total_internal_stress[i]) / Count;} pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; @@ -3021,6 +3039,7 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); pSPARC->std_internal_pressure = sqrt(fabs( ((pow(pSPARC->std_internal_pressure,2.0) + pow(mean_internal_pressure_old,2.0)) * (Count - 1) + pow(pSPARC->internal_pressure,2.0))/Count - pow(pSPARC->mean_internal_pressure,2.0) )); + for (int i = 0; i < 9; i++){pSPARC->std_total_internal_stress[i] = sqrt(fabs( ((pow(pSPARC->std_total_internal_stress[i],2.0) + pow(mean_total_internal_stress_old[i],2.0)) * (Count - 1) + pow(pSPARC->total_internal_stress[i],2.0))/Count - pow(pSPARC->mean_total_internal_stress[i],2.0) ));} pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); @@ -3205,10 +3224,16 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { } // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + fprintf(mdout,":V(1/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel_fractional[3 * atm], pSPARC->ion_vel_fractional[3 * atm + 1], pSPARC->ion_vel_fractional[3 * atm + 2]); + } + } // Print extended system parameters in case of NVT if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ fprintf(mdout,":snose: %.15g\n", pSPARC->snose); @@ -3271,26 +3296,26 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { if (pSPARC->Flag_latvec_scale == 0){ fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] - , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] - , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); + , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] + , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); } else { fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); fprintf(mdout,":LatVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] - , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] - , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); + , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] + , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); } fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI ); fprintf(mdout,":ROTATION_MATRIX: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] - , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] - , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); + , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] + , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * 29421.02648438959); - fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * 29421.02648438959 - ,pSPARC->stress_external[1] * 29421.02648438959 - ,pSPARC->stress_external[2] * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * CONST_HA_BOHR3_GPA); + fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[1] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[2] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[3] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[4] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[5] * CONST_HA_BOHR3_GPA); } // Print temperature fprintf(mdout,":TEL(K): %18.10E\n", pSPARC->elec_T); @@ -3341,6 +3366,15 @@ void RestartMD(SPARC_OBJ *pSPARC) { printf("\nCannot allocate memory for ion velocity array!\n"); exit(EXIT_FAILURE); } + + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel_fractional == NULL) { + printf("\nCannot allocate memory for ion fractional velocity array!\n"); + exit(EXIT_FAILURE); + } + } // Allocate memory for Pack and Unpack to be used later for broadcasting if(pSPARC->RestartFlag == 1){ @@ -3349,10 +3383,10 @@ void RestartMD(SPARC_OBJ *pSPARC) { l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 20)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56 + 20)) * sizeof(double); + l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 56 + 20)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52 + 20)) * sizeof(double); + l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 52 + 20)) * sizeof(double); } else { l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 22) * sizeof(double); @@ -3374,12 +3408,19 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%d",&pSPARC->StopCount); else if (strcmpi(str,":MDSTEP:") == 0) fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) + else if (strcmpi(str,":R(Bohr):") == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + } + } else if (strcmpi(str,":V(Bohr/atu):") == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + } + } else if (strcmpi(str,":V(1/atu):") == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel_fractional[3 * atm], &pSPARC->ion_vel_fractional[3 * atm + 1], &pSPARC->ion_vel_fractional[3 * atm + 2]); + } + } else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) fscanf(rst_fp,"%lf", &pSPARC->snose); else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) @@ -3527,6 +3568,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); + } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); @@ -3549,6 +3591,9 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + MPI_Pack(pSPARC->ion_vel_fractional, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } if(pSPARC->RestartFlag == 1){ MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); @@ -3639,6 +3684,9 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel_fractional, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + } if(pSPARC->RestartFlag == 1){ MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); @@ -3714,7 +3762,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } if(pSPARC->RestartFlag == 1) { pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0)) { // For NPT_NP and NPH the 'reinitialize_mesh_NPT' function is being called from 'fetch_MD_cell_ingredients_restart' after calculating new Jacbdet, cell volume etc reinitialize_mesh_NPT(pSPARC); } } diff --git a/src/md.c b/src/md.c index d2e1df4c..2ab674de 100644 --- a/src/md.c +++ b/src/md.c @@ -78,11 +78,12 @@ void main_MD(SPARC_OBJ *pSPARC) { } } } - pSPARC->internal_pressure = 0; + Calculate_Properties(pSPARC); //Calculate_electronicGroundState(pSPARC); Initialize_MD(pSPARC); + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; // File output_md stores all the desirable properties from a MD run @@ -315,7 +316,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { Calculate_ionic_stress(pSPARC); } // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) && pSPARC->RestartFlag != 1){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -331,7 +332,6 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->maxTimeIter = 100; - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ if(pSPARC->NPT_NP_bmass == 0.0) { if (!rank) { @@ -350,20 +350,6 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { } } - if (rank == 0) { - // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies_NPH_redone_full_flex.log", "w"); - - if (pSPARC->fp_energy == NULL) { - fprintf(stderr, "Error: Could not open energy log file!\n"); - exit(EXIT_FAILURE); - } - - // Optional: Print a header to make the file readable in Excel/Python - fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", - "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); - fflush(pSPARC->fp_energy); - } pSPARC->KE_save = 0.0; fetch_MD_cell_ingredients(pSPARC, false); @@ -412,21 +398,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; //This is computed in function: 'fetch_MD_cell_ingredients_restart' below - - if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - } - else{ - pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; - } pSPARC->maxTimeIter = 100; - pSPARC->KE_save = 0.0; - fetch_MD_cell_ingredients_restart(pSPARC); - + //fetch_MD_cell_ingredients_restart(pSPARC); pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ @@ -447,11 +421,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { //Calculate_ionic_stress(pSPARC); - pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); - exit(EXIT_FAILURE); - } + //Ion vel fractional memory allocation already done within 'RestartMD' function as that is being MPI communicated pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); if (pSPARC->Pm_ion == NULL) { fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); @@ -1465,119 +1435,6 @@ void transpose_and_add(double *matrix1){ matrix1[5] = matrix1[7] = s12; } -void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - int i, j, k; - - double TEMP_TOL = 1e-12; - // Construct LatUVec; - double mag; - for(i = 0; i < 3; i++){ - mag = sqrt(pow(pSPARC->full_lattice[3 * i], 2.0) - + pow(pSPARC->full_lattice[3 * i + 1], 2.0) - + pow(pSPARC->full_lattice[3 * i + 2], 2.0)); - pSPARC->LatUVec[3 * i] = pSPARC->full_lattice[3 * i]/mag; - pSPARC->LatUVec[3 * i + 1] = pSPARC->full_lattice[3 * i + 1]/mag; - pSPARC->LatUVec[3 * i + 2] = pSPARC->full_lattice[3 * i + 2]/mag; - } - - // determinant of 3x3 Jacobian - pSPARC->Jacbdet = 0.0; - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - if(i != j && j != k && k != i) - pSPARC->Jacbdet += ((i - j) * (j - k) * (k - i)/2) * pSPARC->LatUVec[3 * i] * pSPARC->LatUVec[3 * j + 1] * pSPARC->LatUVec[3 * k + 2]; - } - } - } - - if(pSPARC->Jacbdet <= 0){ - if(rank == 0) - printf("ERROR: Volume(det(jacobian)) %lf is <= 0\n", pSPARC->Jacbdet); - exit(EXIT_FAILURE); - } - - // transformation matrix for distance - for(i = 0; i < 9; i++) - pSPARC->metricT[i] = 0.0; - - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - pSPARC->metricT[3*i + j] += pSPARC->LatUVec[3*i + k] * pSPARC->LatUVec[3*j + k]; - } - } - } - - pSPARC->metricT[1] = 2 * pSPARC->metricT[1]; - pSPARC->metricT[2] = 2 * pSPARC->metricT[2]; - pSPARC->metricT[5] = 2 * pSPARC->metricT[5]; - - // transformation matrix for gradient - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - pSPARC->gradT[3*j + i] = (pSPARC->LatUVec[3 * ((j+1) % 3) + (i+1) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+2) % 3] - pSPARC->LatUVec[3 * ((j+1) % 3) + (i+2) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+1) % 3])/pSPARC->Jacbdet; - } - } - - // transformation matrix for laplacian - for(i = 0; i < 9; i++) - pSPARC->lapcT[i] = 0.0; - - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - pSPARC->lapcT[3*i + j] += pSPARC->gradT[3*i + k] * pSPARC->gradT[3*j + k]; - } - } - } - - /* Different cell types for laplacian */ - if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 11; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 12; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 13; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 14; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 15; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 16; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 17; -#ifdef DEBUG - if(!rank) - printf("\n\nCELL_TYP: %d\n\n",pSPARC->cell_typ); -#endif - /* transform the coefficiens of lapacian*/ - // int p, FDn = pSPARC->order/2; - // double dx_inv, dy_inv, dz_inv, dx2_inv, dy2_inv, dz2_inv; - // dx_inv = 1.0 / (pSPARC->delta_x); - // dy_inv = 1.0 / (pSPARC->delta_y); - // dz_inv = 1.0 / (pSPARC->delta_z); - // dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - // dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - // dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - // for (p = 0; p < FDn + 1; p++) { - // pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - // pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - // pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - // pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - // pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - // pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - // pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - // pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - // pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - // pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - // pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - // pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - // } - // TODO: Find maximum eigenvalue of Hamiltionian (= max. eigvalue of -0.5 lap) for non orthogonal periodic systems -} /* Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix @@ -1589,21 +1446,41 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ double old_cell[9]; - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + if (pSPARC->Flag_latvec_scale == 0){ + for (int i = 0; i < 3; i++) { + pSPARC->full_lattice[i] = pSPARC->LatUVec[i] * pSPARC->range_x; + pSPARC->full_lattice[i+3] = pSPARC->LatUVec[i + 3] * pSPARC->range_y; + pSPARC->full_lattice[i+6] = pSPARC->LatUVec[i + 6] * pSPARC->range_z; + } + } + else{ + for (int i = 0; i < 3; i++) { + pSPARC->full_lattice[i] = pSPARC->LatVec[i] * pSPARC->latvec_scale_x; + pSPARC->full_lattice[i+3] = pSPARC->LatVec[i+3] * pSPARC->latvec_scale_y; + pSPARC->full_lattice[i+6] = pSPARC->LatVec[i+6] * pSPARC->latvec_scale_z; + } } - //Compute metric_tensor (G) in real-space (not reciprocal space) cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + if (pSPARC->Flag_latvec_scale == 1){ + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + } + else{ + pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; + } + + //Update LATVEC_SCALE and LatVec + for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles + pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; + } //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat_MD(pSPARC); + Cart2nonCart_transformMat(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) @@ -1651,16 +1528,13 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + for (int i = 0; i < 3; i++) { + pSPARC->full_lattice[i] = pSPARC->LatUVec[i] * pSPARC->range_x; + pSPARC->full_lattice[i+3] = pSPARC->LatUVec[i + 3] * pSPARC->range_y; + pSPARC->full_lattice[i+6] = pSPARC->LatUVec[i + 6] * pSPARC->range_z; } - + //Compute metric_tensor (G) in real-space (not reciprocal space) cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); @@ -1697,8 +1571,20 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + //Update LATVEC_SCALE and LatVec + for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles + pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; + } + if (pSPARC->Flag_latvec_scale == 1){ // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + } + //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat_MD(pSPARC); + Cart2nonCart_transformMat(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) @@ -1710,22 +1596,6 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - } //Update reciprocal lattice vectors, reciprocal metric tensor for (int i = 0; i < 9; i++){ @@ -1754,7 +1624,7 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell@Rotation_matrix.T = old_cell; + //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell = old_cell@rotation_matrix; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); //Initiating cell lattice vectors velocity as zero @@ -1872,8 +1742,10 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// // Calculating kinetic energy of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); + if(pSPARC->RestartFlag == 0){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); + } + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel_fractional, 1); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->metric_tensor, 3, 0.0, pSPARC->Pm_ion, 3); int count = 0; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { @@ -1923,7 +1795,28 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ } pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } - + + #ifdef DEBUG + if (rank == 0) { + printf("within init"); + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } + } + #endif // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// //Initialize constraint stress to 0 @@ -2036,7 +1929,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + if (NPT_NPHscaleVecs[2] == 0){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; @@ -2171,7 +2064,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma Update_metric_tensor_momenta_iteratively_half_step(pSPARC); //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + if (NPT_NPHscaleVecs[2] == 0){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; @@ -2223,9 +2116,11 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma TimeIter++; //it iteration count exceeds max iteration counts, exit if (TimeIter > pSPARC->maxTimeIter){ - printf("%15.7f \n", S_new); - printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); + if (rank == 0){ + printf("%15.7f \n", S_new); + printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } } } #ifdef DEBUG @@ -2263,6 +2158,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); //Update atomic positions and restore ionic velocities cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); + cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel_fractional, 1); //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume @@ -2331,7 +2227,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int } // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + else if (NPT_NPHscaleVecs[2] == 0 ){ gpig[8] = 0; gpig[7] = 0; gpig[6] = 0; @@ -2438,11 +2334,14 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do TimeIter++; //it iteration count exceeds max iteration counts, exit if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); + for(int row = 0; row < 3; row++){ + if (rank == 0){ + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } } } @@ -2562,11 +2461,14 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ TimeIter++; //it iteration count exceeds max iteration counts, exit if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); + for(int row = 0; row < 3; row++){ + if (rank == 0){ + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } } } @@ -2774,9 +2676,10 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + fprintf(output_md,":Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 \n"); if (pSPARC->Flag_latvec_scale == 0){ fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = 1 \n",pSPARC->MDMeth); } else { fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); @@ -2867,6 +2770,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ fprintf(output_md,":ANGLES:\n"); fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(output_md,":VOLUME: %18.10E\n", pSPARC->volumeCell); if (pSPARC->Flag_latvec_scale == 0){ fprintf(output_md,":CELL:\n"); fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); @@ -3231,10 +3135,16 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { } // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + fprintf(mdout,":V(1/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel_fractional[3 * atm], pSPARC->ion_vel_fractional[3 * atm + 1], pSPARC->ion_vel_fractional[3 * atm + 2]); + } + } // Print extended system parameters in case of NVT if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ fprintf(mdout,":snose: %.15g\n", pSPARC->snose); @@ -3297,26 +3207,26 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { if (pSPARC->Flag_latvec_scale == 0){ fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] - , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] - , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); + , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] + , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); } else { fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); fprintf(mdout,":LatVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] - , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] - , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); + , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] + , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); } fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI ); fprintf(mdout,":ROTATION_MATRIX: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] - , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] - , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); + , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] + , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * 29421.02648438959); - fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * 29421.02648438959 - ,pSPARC->stress_external[1] * 29421.02648438959 - ,pSPARC->stress_external[2] * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); + fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * CONST_HA_BOHR3_GPA); + fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[1] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[2] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[3] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[4] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[5] * CONST_HA_BOHR3_GPA); } // Print temperature fprintf(mdout,":TEL(K): %18.10E\n", pSPARC->elec_T); @@ -3367,6 +3277,15 @@ void RestartMD(SPARC_OBJ *pSPARC) { printf("\nCannot allocate memory for ion velocity array!\n"); exit(EXIT_FAILURE); } + + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel_fractional == NULL) { + printf("\nCannot allocate memory for ion fractional velocity array!\n"); + exit(EXIT_FAILURE); + } + } // Allocate memory for Pack and Unpack to be used later for broadcasting if(pSPARC->RestartFlag == 1){ @@ -3375,10 +3294,10 @@ void RestartMD(SPARC_OBJ *pSPARC) { l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 20)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56 + 20)) * sizeof(double); + l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 56 + 20)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52 + 20)) * sizeof(double); + l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 52 + 20)) * sizeof(double); } else { l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 22) * sizeof(double); @@ -3400,12 +3319,19 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%d",&pSPARC->StopCount); else if (strcmpi(str,":MDSTEP:") == 0) fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) + else if (strcmpi(str,":R(Bohr):") == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + } + } else if (strcmpi(str,":V(Bohr/atu):") == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + } + } else if (strcmpi(str,":V(1/atu):") == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel_fractional[3 * atm], &pSPARC->ion_vel_fractional[3 * atm + 1], &pSPARC->ion_vel_fractional[3 * atm + 2]); + } + } else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) fscanf(rst_fp,"%lf", &pSPARC->snose); else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) @@ -3553,6 +3479,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); + } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); @@ -3575,6 +3502,9 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + MPI_Pack(pSPARC->ion_vel_fractional, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } if(pSPARC->RestartFlag == 1){ MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); @@ -3665,6 +3595,9 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel_fractional, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + } if(pSPARC->RestartFlag == 1){ MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); @@ -3740,9 +3673,14 @@ void RestartMD(SPARC_OBJ *pSPARC) { } if(pSPARC->RestartFlag == 1) { pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0)) { // For NPT_NP and NPH the 'reinitialize_mesh_NPT' function is being called from 'fetch_MD_cell_ingredients_restart' after calculating new Jacbdet, cell volume etc reinitialize_mesh_NPT(pSPARC); } + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)||(strcmpi(pSPARC->MDMeth,"NPH") == 0) ){ + fetch_MD_cell_ingredients_restart(pSPARC); + //Now reinitialize mesh based on calculated Jacbdet and other ingredients + reinitialize_mesh_NPT(pSPARC); + } } free(buff); } From 4545e351302d0d4f047f53b8c2ac5c706a725fc2 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Thu, 2 Apr 2026 22:40:29 -0400 Subject: [PATCH 47/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 329 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 240 insertions(+), 89 deletions(-) diff --git a/src/md.c b/src/md.c index 2ab674de..6e7e1d64 100644 --- a/src/md.c +++ b/src/md.c @@ -101,10 +101,8 @@ void main_MD(SPARC_OBJ *pSPARC) { if(pSPARC->RestartFlag == 0){ fprintf(output_md,":MDSTEP: %d\n", 1); fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file } fclose(output_md); } @@ -327,7 +325,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); } else{ - pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; + pSPARC->initialLatVecLength[0] = 1; pSPARC->initialLatVecLength[1] = 1; pSPARC->initialLatVecLength[2] = 1; } pSPARC->maxTimeIter = 100; @@ -401,7 +399,8 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->maxTimeIter = 100; //fetch_MD_cell_ingredients_restart(pSPARC); - + pSPARC->KE_save = 0.0; + pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -410,6 +409,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + + if(strcmpi(pSPARC->MDMeth,"NPH")){ pSPARC->NPT_NP_qmass = 0; pSPARC->SNOSE[0] = 1.0; @@ -422,9 +424,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { //Calculate_ionic_stress(pSPARC); //Ion vel fractional memory allocation already done within 'RestartMD' function as that is being MPI communicated - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); + pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic fractional velocity array.\n"); exit(EXIT_FAILURE); } } @@ -1397,7 +1399,7 @@ void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double * MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); //Calculate initial hamitonian - if ((pSPARC->MDCount == 1)) { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)){ NPT_NP_and_NPH_init_hamiltonian(pSPARC); } //NPT_NPH_main routine @@ -1435,6 +1437,119 @@ void transpose_and_add(double *matrix1){ matrix1[5] = matrix1[7] = s12; } +void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + int i, j, k; + + double TEMP_TOL = 1e-12; + // Construct LatUVec; + double mag; + for(i = 0; i < 3; i++){ + mag = sqrt(pow(pSPARC->full_lattice[3 * i], 2.0) + + pow(pSPARC->full_lattice[3 * i + 1], 2.0) + + pow(pSPARC->full_lattice[3 * i + 2], 2.0)); + pSPARC->LatUVec[3 * i] = pSPARC->full_lattice[3 * i]/mag; + pSPARC->LatUVec[3 * i + 1] = pSPARC->full_lattice[3 * i + 1]/mag; + pSPARC->LatUVec[3 * i + 2] = pSPARC->full_lattice[3 * i + 2]/mag; + } + + // determinant of 3x3 Jacobian + pSPARC->Jacbdet = 0.0; + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + if(i != j && j != k && k != i) + pSPARC->Jacbdet += ((i - j) * (j - k) * (k - i)/2) * pSPARC->LatUVec[3 * i] * pSPARC->LatUVec[3 * j + 1] * pSPARC->LatUVec[3 * k + 2]; + } + } + } + + if(pSPARC->Jacbdet <= 0){ + if(rank == 0) + printf("ERROR: Volume(det(jacobian)) %lf is <= 0\n", pSPARC->Jacbdet); + exit(EXIT_FAILURE); + } + + // transformation matrix for distance + for(i = 0; i < 9; i++) + pSPARC->metricT[i] = 0.0; + + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + pSPARC->metricT[3*i + j] += pSPARC->LatUVec[3*i + k] * pSPARC->LatUVec[3*j + k]; + } + } + } + + pSPARC->metricT[1] = 2 * pSPARC->metricT[1]; + pSPARC->metricT[2] = 2 * pSPARC->metricT[2]; + pSPARC->metricT[5] = 2 * pSPARC->metricT[5]; + + // transformation matrix for gradient + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + pSPARC->gradT[3*j + i] = (pSPARC->LatUVec[3 * ((j+1) % 3) + (i+1) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+2) % 3] - pSPARC->LatUVec[3 * ((j+1) % 3) + (i+2) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+1) % 3])/pSPARC->Jacbdet; + } + } + + // transformation matrix for laplacian + for(i = 0; i < 9; i++) + pSPARC->lapcT[i] = 0.0; + + for(i = 0; i < 3; i++){ + for(j = 0; j < 3; j++){ + for(k = 0; k < 3; k++){ + pSPARC->lapcT[3*i + j] += pSPARC->gradT[3*i + k] * pSPARC->gradT[3*j + k]; + } + } + } + + /* Different cell types for laplacian */ + if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 11; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 12; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 13; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) + pSPARC->cell_typ = 14; + else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 15; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 16; + else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) + pSPARC->cell_typ = 17; +#ifdef DEBUG + if(!rank) + printf("\n\nCELL_TYP: %d\n\n",pSPARC->cell_typ); +#endif + /* transform the coefficiens of lapacian*/ + // int p, FDn = pSPARC->order/2; + // double dx_inv, dy_inv, dz_inv, dx2_inv, dy2_inv, dz2_inv; + // dx_inv = 1.0 / (pSPARC->delta_x); + // dy_inv = 1.0 / (pSPARC->delta_y); + // dz_inv = 1.0 / (pSPARC->delta_z); + // dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + // dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + // dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + // for (p = 0; p < FDn + 1; p++) { + // pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + // pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + // pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + // pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + // pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + // pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + // pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + // pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + // pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + // pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + // pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + // pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + // } + // TODO: Find maximum eigenvalue of Hamiltionian (= max. eigvalue of -0.5 lap) for non orthogonal periodic systems +} /* Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix @@ -1460,29 +1575,48 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ pSPARC->full_lattice[i+3] = pSPARC->LatVec[i+3] * pSPARC->latvec_scale_y; pSPARC->full_lattice[i+6] = pSPARC->LatVec[i+6] * pSPARC->latvec_scale_z; } + } //Compute metric_tensor (G) in real-space (not reciprocal space) cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - } + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + } else{ - pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; + pSPARC->initialLatVecLength[0] = 1; pSPARC->initialLatVecLength[1] = 1; pSPARC->initialLatVecLength[2] = 1; } - //Update LATVEC_SCALE and LatVec - for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles - pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; - } //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); + Cart2nonCart_transformMat_MD(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + printf("Volume cell %lf \n",pSPARC->volumeCell); + printf("range_x %lf \n",pSPARC->range_x); + printf("range_y %lf \n",pSPARC->range_y); + printf("range_z %lf \n",pSPARC->range_z); + + for (int i = 0; i < 9; i++){ + printf("FUll lattice[%d] is %lf \n",i,pSPARC->full_lattice[i]); + } + + if (pSPARC->Flag_latvec_scale == 1){ + for (int i = 0; i < 9; i++){ + printf("LatVec[%d] is %lf \n",i,pSPARC->LatVec[i]); + } + } + if (pSPARC->Flag_latvec_scale == 0){ + for (int i = 0; i < 9; i++){ + printf("LatUVec[%d] is %lf \n",i,pSPARC->LatUVec[i]); + } + } + exit(EXIT_FAILURE); // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); @@ -1528,13 +1662,16 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + //Compute Cell lattice vectors (scaled by LATVEC scale) - for (int i = 0; i < 3; i++) { - pSPARC->full_lattice[i] = pSPARC->LatUVec[i] * pSPARC->range_x; - pSPARC->full_lattice[i+3] = pSPARC->LatUVec[i + 3] * pSPARC->range_y; - pSPARC->full_lattice[i+6] = pSPARC->LatUVec[i + 6] * pSPARC->range_z; + int row; + for (row = 0; row < 3; row++) { + pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; } - + //Compute metric_tensor (G) in real-space (not reciprocal space) cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); @@ -1571,20 +1708,8 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - //Update LATVEC_SCALE and LatVec - for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles - pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; - } - if (pSPARC->Flag_latvec_scale == 1){ // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - } - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); + Cart2nonCart_transformMat_MD(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) @@ -1596,6 +1721,22 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + } //Update reciprocal lattice vectors, reciprocal metric tensor for (int i = 0; i < 9; i++){ @@ -1624,7 +1765,7 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell = old_cell@rotation_matrix; + //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell@Rotation_matrix.T = old_cell; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); //Initiating cell lattice vectors velocity as zero @@ -1742,9 +1883,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// // Calculating kinetic energy of ions - if(pSPARC->RestartFlag == 0){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); - } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel_fractional, 1); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->metric_tensor, 3, 0.0, pSPARC->Pm_ion, 3); int count = 0; @@ -1861,17 +2000,13 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma double baro_const3 = 1.0 / baro_const1; - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - - pSPARC->KE = pSPARC->KE_save; - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// double factor; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) if (pSPARC->NPT_NP_qmass > 0){ pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; + factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof * ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; #ifdef DEBUG if (rank == 0) { @@ -2158,7 +2293,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); //Update atomic positions and restore ionic velocities cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); - cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel_fractional, 1); + //cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel_fractional, 1); //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume @@ -3140,9 +3275,9 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); } if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - fprintf(mdout,":V(1/atu):\n"); + fprintf(mdout,":Pm_ion:\n"); for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel_fractional[3 * atm], pSPARC->ion_vel_fractional[3 * atm + 1], pSPARC->ion_vel_fractional[3 * atm + 2]); + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->Pm_ion[3 * atm], pSPARC->Pm_ion[3 * atm + 1], pSPARC->Pm_ion[3 * atm + 2]); } } // Print extended system parameters in case of NVT @@ -3196,14 +3331,21 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPH_bmass); fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); } - fprintf(mdout,":lattice_avg_velo: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + fprintf(mdout,":KE: %.15g\n",pSPARC->KE); + fprintf(mdout,":Kbaro: %.15g\n",pSPARC->Kbaro); + fprintf(mdout,":Ubaro: %.15g\n",pSPARC->Ubaro); + fprintf(mdout,":kinetic_stress: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->kinetic_stress[0], pSPARC->kinetic_stress[1], pSPARC->kinetic_stress[2] + , pSPARC->kinetic_stress[3], pSPARC->kinetic_stress[4], pSPARC->kinetic_stress[5] + , pSPARC->kinetic_stress[6], pSPARC->kinetic_stress[7], pSPARC->kinetic_stress[8]); + fprintf(mdout,":Pm_metric_tensor: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // velocity of lattice if (pSPARC->Flag_latvec_scale == 0){ fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] @@ -3280,9 +3422,9 @@ void RestartMD(SPARC_OBJ *pSPARC) { if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel_fractional == NULL) { - printf("\nCannot allocate memory for ion fractional velocity array!\n"); + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + printf("\nCannot allocate memory for ion momentum array!\n"); exit(EXIT_FAILURE); } } @@ -3294,10 +3436,10 @@ void RestartMD(SPARC_OBJ *pSPARC) { l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 20)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 56 + 20)) * sizeof(double); + l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 56 + 32)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 52 + 20)) * sizeof(double); + l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 52 + 32)) * sizeof(double); } else { l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 22) * sizeof(double); @@ -3327,9 +3469,9 @@ void RestartMD(SPARC_OBJ *pSPARC) { for(atm = 0; atm < pSPARC->n_atom; atm++){ fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); } - } else if (strcmpi(str,":V(1/atu):") == 0){ + } else if (strcmpi(str,":Pm_ion:") == 0){ for(atm = 0; atm < pSPARC->n_atom; atm++){ - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel_fractional[3 * atm], &pSPARC->ion_vel_fractional[3 * atm + 1], &pSPARC->ion_vel_fractional[3 * atm + 2]); + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->Pm_ion[3 * atm], &pSPARC->Pm_ion[3 * atm + 1], &pSPARC->Pm_ion[3 * atm + 2]); } } else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) @@ -3445,22 +3587,31 @@ void RestartMD(SPARC_OBJ *pSPARC) { else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ if (strcmpi(str,":NPH_BMASS:") == 0) fscanf(rst_fp,"%lf", &pSPARC->NPH_bmass); else if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); } - else if (strcmpi(str,":LATTICE_AVG_VELOCITY:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[0]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[1]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[2]); - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[3]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[4]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[5]); - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[6]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[7]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[8]); - + else if (strcmpi(str,":KE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->KE); + else if (strcmpi(str,":Kbaro:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->Kbaro); + else if (strcmpi(str,":Ubaro:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->Ubaro); + else if (strcmpi(str,":kinetic_stress:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[0]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[1]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[2]); + fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[3]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[4]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[5]); + fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[6]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[7]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[8]); + } else if (strcmpi(str,":Pm_metric_tensor:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[0]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[1]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[2]); + fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[3]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[4]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[5]); + fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[6]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[7]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[8]); } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); for (int i = 0; i < 3; i++){pSPARC->initialLatVecAngles[i] = cos(M_PI / 180 * pSPARC->initialLatVecAngles[i]);} } else if (strcmpi(str,":CELL:") == 0) { - fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); + fscanf(rst_fp,"%lf", &pSPARC->range_x); fscanf(rst_fp,"%lf", &pSPARC->range_y); fscanf(rst_fp,"%lf", &pSPARC->range_z); } else if (strcmpi(str,":LatUVec:") == 0) { fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); @@ -3468,18 +3619,10 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->range_x = pSPARC->initialLatVecLength[0]*pSPARC->latvec_scale_x; - pSPARC->range_y = pSPARC->initialLatVecLength[1]*pSPARC->latvec_scale_y; - pSPARC->range_z = pSPARC->initialLatVecLength[2]*pSPARC->latvec_scale_z; } else if (strcmpi(str,":LatVec:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); - } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); @@ -3502,10 +3645,10 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - MPI_Pack(pSPARC->ion_vel_fractional, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } if(pSPARC->RestartFlag == 1){ + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + MPI_Pack(pSPARC->Pm_ion, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->mean_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); @@ -3559,7 +3702,11 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Pack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } - MPI_Pack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->Kbaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->Ubaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->kinetic_stress, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); @@ -3593,12 +3740,12 @@ void RestartMD(SPARC_OBJ *pSPARC) { position = 0; MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel_fractional, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - } - if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + MPI_Unpack(buff, l_buff, &position, pSPARC->Pm_ion, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + } MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); @@ -3652,7 +3799,11 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Unpack(buff, l_buff, &position, &pSPARC->NPH_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); } - MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->Kbaro, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->Ubaro, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->kinetic_stress, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); From 77f04fdc06a23ddaa4c3938ee892047538c13c06 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Fri, 3 Apr 2026 11:28:57 -0400 Subject: [PATCH 48/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 89 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/src/md.c b/src/md.c index 6e7e1d64..42438d59 100644 --- a/src/md.c +++ b/src/md.c @@ -412,7 +412,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - if(strcmpi(pSPARC->MDMeth,"NPH")){ + if(strcmpi(pSPARC->MDMeth,"NPH")==0){ pSPARC->NPT_NP_qmass = 0; pSPARC->SNOSE[0] = 1.0; pSPARC->SNOSE[1] = 0.0; @@ -1597,14 +1597,14 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ Cart2nonCart_transformMat_MD(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - printf("Volume cell %lf \n",pSPARC->volumeCell); - printf("range_x %lf \n",pSPARC->range_x); - printf("range_y %lf \n",pSPARC->range_y); - printf("range_z %lf \n",pSPARC->range_z); + // printf("Volume cell %lf \n",pSPARC->volumeCell); + // printf("range_x %lf \n",pSPARC->range_x); + // printf("range_y %lf \n",pSPARC->range_y); + // printf("range_z %lf \n",pSPARC->range_z); - for (int i = 0; i < 9; i++){ - printf("FUll lattice[%d] is %lf \n",i,pSPARC->full_lattice[i]); - } + // for (int i = 0; i < 9; i++){ + // printf("FUll lattice[%d] is %lf \n",i,pSPARC->full_lattice[i]); + // } if (pSPARC->Flag_latvec_scale == 1){ for (int i = 0; i < 9; i++){ @@ -1616,7 +1616,7 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ printf("LatUVec[%d] is %lf \n",i,pSPARC->LatUVec[i]); } } - exit(EXIT_FAILURE); + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); @@ -1651,7 +1651,7 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); // Now computing reciprocal metric tensor, cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - + printf("here"); } void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ @@ -1999,7 +1999,23 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } double baro_const3 = 1.0 / baro_const1; - + // printf("QMASS: %lf\n",pSPARC->NPT_NP_qmass); + // printf("SNOSE[0] %lf \n",pSPARC->SNOSE[0]); + // printf("SNOSE[1] %lf \n",pSPARC->SNOSE[1]); + // printf("SNOSE[2] %lf \n",pSPARC->SNOSE[2]); + // printf("KE %lf \n",pSPARC->KE); + // printf("Kbaro %lf \n",pSPARC->Kbaro); + // printf("Ubaro %lf \n",pSPARC->Ubaro); + // printf("InitHamil %lf \n",pSPARC->init_Hamil_NPT_NP); + // //; + // if (rank == 0){ + // printf(":Pm_ion:\n"); + // for(int atm = 0; atm < pSPARC->n_atom; atm++){ + // printf("%18.10E %18.10E %18.10E\n", pSPARC->Pm_ion[3 * atm], pSPARC->Pm_ion[3 * atm + 1], pSPARC->Pm_ion[3 * atm + 2]); + // } + // } + // printf("Intial angles %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); + // exit(EXIT_FAILURE); // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// double factor; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) @@ -3331,7 +3347,6 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPH_bmass); @@ -3362,7 +3377,7 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * CONST_HA_BOHR3_GPA); + fprintf(mdout,":EXTERNAL_PRESSURE: %.15g\n", pSPARC->pressure_external * CONST_HA_BOHR3_GPA); fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * CONST_HA_BOHR3_GPA ,pSPARC->stress_external[1] * CONST_HA_BOHR3_GPA ,pSPARC->stress_external[2] * CONST_HA_BOHR3_GPA @@ -3489,6 +3504,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); pSPARC->mean_internal_pressure /= CONST_HA_BOHR3_GPA; pSPARC->std_internal_pressure /= CONST_HA_BOHR3_GPA; }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); @@ -3574,11 +3590,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) + if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) fscanf(rst_fp,"%lf", &pSPARC->SNOSE[0]); else if (strcmpi(str,":NPT_NP_SNOSE[1]:") == 0) fscanf(rst_fp,"%lf", &pSPARC->SNOSE[1]); @@ -3588,12 +3600,10 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - if (strcmpi(str,":NPH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPH_bmass); - else if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) + if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); } - else if (strcmpi(str,":KE:") == 0) + if (strcmpi(str,":KE:") == 0) fscanf(rst_fp,"%lf", &pSPARC->KE); else if (strcmpi(str,":Kbaro:") == 0) fscanf(rst_fp,"%lf", &pSPARC->Kbaro); @@ -3618,6 +3628,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); + fscanf(rst_fp, "%*[^\n]\n"); } else if (strcmpi(str,":LatVec:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); @@ -3691,30 +3702,28 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->SNOSE, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Pack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } MPI_Pack(&pSPARC->KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->Kbaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->Ubaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->kinetic_stress, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->kinetic_stress, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); if (pSPARC->Flag_latvec_scale == 0){ + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } else if (pSPARC->Flag_latvec_scale == 1){ + MPI_Pack(&pSPARC->latvec_scale_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->latvec_scale_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->latvec_scale_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); @@ -3788,15 +3797,10 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[0], 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[1], 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[2], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->SNOSE, 3, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPH_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); } MPI_Unpack(buff, l_buff, &position, &pSPARC->KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); @@ -3805,13 +3809,16 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Unpack(buff, l_buff, &position, pSPARC->kinetic_stress, 9, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); if (pSPARC->Flag_latvec_scale == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->LatUVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); } else if (pSPARC->Flag_latvec_scale == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->LatVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); } MPI_Unpack(buff, l_buff, &position, pSPARC->rotation_matrix, 9, MPI_DOUBLE, MPI_COMM_WORLD); From fdfa1bc07749434f5e82ddb990489bec9b2d4231 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Fri, 3 Apr 2026 12:46:36 -0400 Subject: [PATCH 49/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/MD_printing_refined_fractional.c | 360 ++++++++++++++++----------- src/include/isddft.h | 1 + src/md.c | 308 ++++++++++++++--------- 3 files changed, 406 insertions(+), 263 deletions(-) diff --git a/src/MD_printing_refined_fractional.c b/src/MD_printing_refined_fractional.c index 5c51933a..42438d59 100644 --- a/src/MD_printing_refined_fractional.c +++ b/src/MD_printing_refined_fractional.c @@ -78,11 +78,12 @@ void main_MD(SPARC_OBJ *pSPARC) { } } } - pSPARC->internal_pressure = 0; + Calculate_Properties(pSPARC); //Calculate_electronicGroundState(pSPARC); Initialize_MD(pSPARC); + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; // File output_md stores all the desirable properties from a MD run @@ -100,10 +101,9 @@ void main_MD(SPARC_OBJ *pSPARC) { if(pSPARC->RestartFlag == 0){ fprintf(output_md,":MDSTEP: %d\n", 1); fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file } - fclose(output_md); } @@ -314,7 +314,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { Calculate_ionic_stress(pSPARC); } // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) && pSPARC->RestartFlag != 1){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -325,7 +325,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); } else{ - pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; + pSPARC->initialLatVecLength[0] = 1; pSPARC->initialLatVecLength[1] = 1; pSPARC->initialLatVecLength[2] = 1; } pSPARC->maxTimeIter = 100; @@ -334,7 +334,6 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { if(pSPARC->NPT_NP_bmass == 0.0) { if (!rank) { printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); - printf("herere"); exit(EXIT_FAILURE); } } @@ -344,26 +343,11 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { if(pSPARC->NPH_bmass == 0.0) { if (!rank) { printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); - printf("he1"); exit(EXIT_FAILURE); } } } - if (rank == 0) { - // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies_NPH2.log", "w"); - - if (pSPARC->fp_energy == NULL) { - fprintf(stderr, "Error: Could not open energy log file!\n"); - exit(EXIT_FAILURE); - } - - // Optional: Print a header to make the file readable in Excel/Python - fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", - "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); - fflush(pSPARC->fp_energy); - } pSPARC->KE_save = 0.0; fetch_MD_cell_ingredients(pSPARC, false); @@ -412,22 +396,11 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; //This is computed in function: 'fetch_MD_cell_ingredients_restart' below - - if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - } - else{ - pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; - } pSPARC->maxTimeIter = 100; + //fetch_MD_cell_ingredients_restart(pSPARC); pSPARC->KE_save = 0.0; - fetch_MD_cell_ingredients_restart(pSPARC); - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -436,7 +409,10 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - if(strcmpi(pSPARC->MDMeth,"NPH")){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + + + if(strcmpi(pSPARC->MDMeth,"NPH")==0){ pSPARC->NPT_NP_qmass = 0; pSPARC->SNOSE[0] = 1.0; pSPARC->SNOSE[1] = 0.0; @@ -447,14 +423,10 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { //Calculate_ionic_stress(pSPARC); + //Ion vel fractional memory allocation already done within 'RestartMD' function as that is being MPI communicated pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); if (pSPARC->ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); - exit(EXIT_FAILURE); - } - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); + fprintf(stderr, "Error: Memory allocation failed for ionic fractional velocity array.\n"); exit(EXIT_FAILURE); } } @@ -571,6 +543,10 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; + for (int i = 0; i < 9; i++){ + pSPARC->mean_total_internal_stress[i] = 0.0; + pSPARC->std_total_internal_stress[i] = 0.0; + } } #endif } @@ -1423,7 +1399,7 @@ void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double * MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); //Calculate initial hamitonian - if ((pSPARC->MDCount == 1)) { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)){ NPT_NP_and_NPH_init_hamiltonian(pSPARC); } //NPT_NPH_main routine @@ -1585,23 +1561,62 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ double old_cell[9]; - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + if (pSPARC->Flag_latvec_scale == 0){ + for (int i = 0; i < 3; i++) { + pSPARC->full_lattice[i] = pSPARC->LatUVec[i] * pSPARC->range_x; + pSPARC->full_lattice[i+3] = pSPARC->LatUVec[i + 3] * pSPARC->range_y; + pSPARC->full_lattice[i+6] = pSPARC->LatUVec[i + 6] * pSPARC->range_z; + } } + else{ + for (int i = 0; i < 3; i++) { + pSPARC->full_lattice[i] = pSPARC->LatVec[i] * pSPARC->latvec_scale_x; + pSPARC->full_lattice[i+3] = pSPARC->LatVec[i+3] * pSPARC->latvec_scale_y; + pSPARC->full_lattice[i+6] = pSPARC->LatVec[i+6] * pSPARC->latvec_scale_z; + } + } //Compute metric_tensor (G) in real-space (not reciprocal space) cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + if (pSPARC->Flag_latvec_scale == 1){ + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + } + else{ + pSPARC->initialLatVecLength[0] = 1; pSPARC->initialLatVecLength[1] = 1; pSPARC->initialLatVecLength[2] = 1; + } + //Update LatUVec, Jacbdet, metricT, gradT, lapcT Cart2nonCart_transformMat_MD(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + // printf("Volume cell %lf \n",pSPARC->volumeCell); + // printf("range_x %lf \n",pSPARC->range_x); + // printf("range_y %lf \n",pSPARC->range_y); + // printf("range_z %lf \n",pSPARC->range_z); + + // for (int i = 0; i < 9; i++){ + // printf("FUll lattice[%d] is %lf \n",i,pSPARC->full_lattice[i]); + // } + + if (pSPARC->Flag_latvec_scale == 1){ + for (int i = 0; i < 9; i++){ + printf("LatVec[%d] is %lf \n",i,pSPARC->LatVec[i]); + } + } + if (pSPARC->Flag_latvec_scale == 0){ + for (int i = 0; i < 9; i++){ + printf("LatUVec[%d] is %lf \n",i,pSPARC->LatUVec[i]); + } + } + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); @@ -1636,7 +1651,7 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); // Now computing reciprocal metric tensor, cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - + printf("here"); } void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ @@ -1868,8 +1883,8 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// // Calculating kinetic energy of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel_fractional, 1); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->metric_tensor, 3, 0.0, pSPARC->Pm_ion, 3); int count = 0; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { @@ -1919,7 +1934,28 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ } pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } - + + #ifdef DEBUG + if (rank == 0) { + printf("within init"); + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } + } + #endif // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// //Initialize constraint stress to 0 @@ -1963,18 +1999,30 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } double baro_const3 = 1.0 / baro_const1; - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - - pSPARC->KE = pSPARC->KE_save; - + // printf("QMASS: %lf\n",pSPARC->NPT_NP_qmass); + // printf("SNOSE[0] %lf \n",pSPARC->SNOSE[0]); + // printf("SNOSE[1] %lf \n",pSPARC->SNOSE[1]); + // printf("SNOSE[2] %lf \n",pSPARC->SNOSE[2]); + // printf("KE %lf \n",pSPARC->KE); + // printf("Kbaro %lf \n",pSPARC->Kbaro); + // printf("Ubaro %lf \n",pSPARC->Ubaro); + // printf("InitHamil %lf \n",pSPARC->init_Hamil_NPT_NP); + // //; + // if (rank == 0){ + // printf(":Pm_ion:\n"); + // for(int atm = 0; atm < pSPARC->n_atom; atm++){ + // printf("%18.10E %18.10E %18.10E\n", pSPARC->Pm_ion[3 * atm], pSPARC->Pm_ion[3 * atm + 1], pSPARC->Pm_ion[3 * atm + 2]); + // } + // } + // printf("Intial angles %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); + // exit(EXIT_FAILURE); // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// double factor; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) if (pSPARC->NPT_NP_qmass > 0){ pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; + factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof * ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; #ifdef DEBUG if (rank == 0) { @@ -2032,7 +2080,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + if (NPT_NPHscaleVecs[2] == 0){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; @@ -2119,12 +2167,17 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } #endif - // For printing, convert the total internal stress and the kinetic stress to cartesian coordinates - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); + // For printing, convert the total internal stress, constraint stress and the kinetic stress to cartesian coordinates + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); //Already divided by volume earlier cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->total_internal_stress, 3); //Mutliplied by 2 so as to remove the effect of previous divisions by 2 in the kinetic_stress, internal_stress_fractional cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, -2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->constraint_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->constraint_stress, 3); + + // Obtain updated velocities in cartesian coordinates for use in MD_QOI function cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); @@ -2162,7 +2215,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma Update_metric_tensor_momenta_iteratively_half_step(pSPARC); //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + if (NPT_NPHscaleVecs[2] == 0){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; @@ -2214,9 +2267,11 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma TimeIter++; //it iteration count exceeds max iteration counts, exit if (TimeIter > pSPARC->maxTimeIter){ - printf("%15.7f \n", S_new); - printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); + if (rank == 0){ + printf("%15.7f \n", S_new); + printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } } } #ifdef DEBUG @@ -2254,6 +2309,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); //Update atomic positions and restore ionic velocities cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); + //cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel_fractional, 1); //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume @@ -2322,7 +2378,7 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int } // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ + else if (NPT_NPHscaleVecs[2] == 0 ){ gpig[8] = 0; gpig[7] = 0; gpig[6] = 0; @@ -2429,11 +2485,14 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do TimeIter++; //it iteration count exceeds max iteration counts, exit if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); + for(int row = 0; row < 3; row++){ + if (rank == 0){ + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } } } @@ -2553,11 +2612,14 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ TimeIter++; //it iteration count exceeds max iteration counts, exit if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); + for(int row = 0; row < 3; row++){ + if (rank == 0){ + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } } } @@ -3229,9 +3291,9 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); } if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - fprintf(mdout,":V(1/atu):\n"); + fprintf(mdout,":Pm_ion:\n"); for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel_fractional[3 * atm], pSPARC->ion_vel_fractional[3 * atm + 1], pSPARC->ion_vel_fractional[3 * atm + 2]); + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->Pm_ion[3 * atm], pSPARC->Pm_ion[3 * atm + 1], pSPARC->Pm_ion[3 * atm + 2]); } } // Print extended system parameters in case of NVT @@ -3286,13 +3348,19 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPH_bmass); fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); } - fprintf(mdout,":lattice_avg_velo: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice + fprintf(mdout,":KE: %.15g\n",pSPARC->KE); + fprintf(mdout,":Kbaro: %.15g\n",pSPARC->Kbaro); + fprintf(mdout,":Ubaro: %.15g\n",pSPARC->Ubaro); + fprintf(mdout,":kinetic_stress: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->kinetic_stress[0], pSPARC->kinetic_stress[1], pSPARC->kinetic_stress[2] + , pSPARC->kinetic_stress[3], pSPARC->kinetic_stress[4], pSPARC->kinetic_stress[5] + , pSPARC->kinetic_stress[6], pSPARC->kinetic_stress[7], pSPARC->kinetic_stress[8]); + fprintf(mdout,":Pm_metric_tensor: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // velocity of lattice if (pSPARC->Flag_latvec_scale == 0){ fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] @@ -3309,7 +3377,7 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * CONST_HA_BOHR3_GPA); + fprintf(mdout,":EXTERNAL_PRESSURE: %.15g\n", pSPARC->pressure_external * CONST_HA_BOHR3_GPA); fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * CONST_HA_BOHR3_GPA ,pSPARC->stress_external[1] * CONST_HA_BOHR3_GPA ,pSPARC->stress_external[2] * CONST_HA_BOHR3_GPA @@ -3369,9 +3437,9 @@ void RestartMD(SPARC_OBJ *pSPARC) { if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel_fractional == NULL) { - printf("\nCannot allocate memory for ion fractional velocity array!\n"); + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + printf("\nCannot allocate memory for ion momentum array!\n"); exit(EXIT_FAILURE); } } @@ -3383,10 +3451,10 @@ void RestartMD(SPARC_OBJ *pSPARC) { l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 20)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 56 + 20)) * sizeof(double); + l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 56 + 32)) * sizeof(double); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 52 + 20)) * sizeof(double); + l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 52 + 32)) * sizeof(double); } else { l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 22) * sizeof(double); @@ -3416,9 +3484,9 @@ void RestartMD(SPARC_OBJ *pSPARC) { for(atm = 0; atm < pSPARC->n_atom; atm++){ fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); } - } else if (strcmpi(str,":V(1/atu):") == 0){ + } else if (strcmpi(str,":Pm_ion:") == 0){ for(atm = 0; atm < pSPARC->n_atom; atm++){ - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel_fractional[3 * atm], &pSPARC->ion_vel_fractional[3 * atm + 1], &pSPARC->ion_vel_fractional[3 * atm + 2]); + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->Pm_ion[3 * atm], &pSPARC->Pm_ion[3 * atm + 1], &pSPARC->Pm_ion[3 * atm + 2]); } } else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) @@ -3436,6 +3504,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); pSPARC->mean_internal_pressure /= CONST_HA_BOHR3_GPA; pSPARC->std_internal_pressure /= CONST_HA_BOHR3_GPA; }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); @@ -3521,11 +3590,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) + if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) fscanf(rst_fp,"%lf", &pSPARC->SNOSE[0]); else if (strcmpi(str,":NPT_NP_SNOSE[1]:") == 0) fscanf(rst_fp,"%lf", &pSPARC->SNOSE[1]); @@ -3534,41 +3599,41 @@ void RestartMD(SPARC_OBJ *pSPARC) { else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (strcmpi(str,":NPH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPH_bmass); - else if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); } - else if (strcmpi(str,":LATTICE_AVG_VELOCITY:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[0]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[1]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[2]); - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[3]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[4]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[5]); - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[6]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[7]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[8]); - + if (strcmpi(str,":KE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->KE); + else if (strcmpi(str,":Kbaro:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->Kbaro); + else if (strcmpi(str,":Ubaro:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->Ubaro); + else if (strcmpi(str,":kinetic_stress:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[0]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[1]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[2]); + fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[3]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[4]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[5]); + fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[6]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[7]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[8]); + } else if (strcmpi(str,":Pm_metric_tensor:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[0]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[1]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[2]); + fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[3]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[4]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[5]); + fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[6]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[7]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[8]); } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); for (int i = 0; i < 3; i++){pSPARC->initialLatVecAngles[i] = cos(M_PI / 180 * pSPARC->initialLatVecAngles[i]);} } else if (strcmpi(str,":CELL:") == 0) { - fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); + fscanf(rst_fp,"%lf", &pSPARC->range_x); fscanf(rst_fp,"%lf", &pSPARC->range_y); fscanf(rst_fp,"%lf", &pSPARC->range_z); } else if (strcmpi(str,":LatUVec:") == 0) { fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); + fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->range_x = pSPARC->initialLatVecLength[0]*pSPARC->latvec_scale_x; - pSPARC->range_y = pSPARC->initialLatVecLength[1]*pSPARC->latvec_scale_y; - pSPARC->range_z = pSPARC->initialLatVecLength[2]*pSPARC->latvec_scale_z; } else if (strcmpi(str,":LatVec:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); - } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); @@ -3591,10 +3656,10 @@ void RestartMD(SPARC_OBJ *pSPARC) { MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - MPI_Pack(pSPARC->ion_vel_fractional, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } if(pSPARC->RestartFlag == 1){ + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + MPI_Pack(pSPARC->Pm_ion, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->mean_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); @@ -3637,26 +3702,28 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->SNOSE, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Pack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } - MPI_Pack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->Kbaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->Ubaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->kinetic_stress, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); if (pSPARC->Flag_latvec_scale == 0){ + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } else if (pSPARC->Flag_latvec_scale == 1){ + MPI_Pack(&pSPARC->latvec_scale_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->latvec_scale_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->latvec_scale_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); } MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); @@ -3682,12 +3749,12 @@ void RestartMD(SPARC_OBJ *pSPARC) { position = 0; MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel_fractional, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - } - if(pSPARC->RestartFlag == 1){ + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + MPI_Unpack(buff, l_buff, &position, pSPARC->Pm_ion, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + } MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); @@ -3730,26 +3797,28 @@ void RestartMD(SPARC_OBJ *pSPARC) { } else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[0], 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[1], 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[2], 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->SNOSE, 3, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); } else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPH_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); } - MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->Kbaro, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->Ubaro, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->kinetic_stress, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); if (pSPARC->Flag_latvec_scale == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->LatUVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); } else if (pSPARC->Flag_latvec_scale == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, pSPARC->LatVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); } MPI_Unpack(buff, l_buff, &position, pSPARC->rotation_matrix, 9, MPI_DOUBLE, MPI_COMM_WORLD); @@ -3765,6 +3834,11 @@ void RestartMD(SPARC_OBJ *pSPARC) { if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0)) { // For NPT_NP and NPH the 'reinitialize_mesh_NPT' function is being called from 'fetch_MD_cell_ingredients_restart' after calculating new Jacbdet, cell volume etc reinitialize_mesh_NPT(pSPARC); } + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)||(strcmpi(pSPARC->MDMeth,"NPH") == 0) ){ + fetch_MD_cell_ingredients_restart(pSPARC); + //Now reinitialize mesh based on calculated Jacbdet and other ingredients + reinitialize_mesh_NPT(pSPARC); + } } free(buff); } diff --git a/src/include/isddft.h b/src/include/isddft.h index 005e8d46..38c66a13 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -920,6 +920,7 @@ typedef struct _SPARC_OBJ{ double init_Hamil_NPT_NP; // initial Hamiltonian in NPT_NP ensemble double init_Hamil_NPH; // initial Hamiltonian in NPH ensemble double KE_save; + double t_md; //NPT_NP_specific double NPT_NP_qmass; // fictitious mass of thermostat (qmass) used in NPT_NP double NPT_NP_bmass; // fictitious mass of barostat (bmass) used in NPT_NP diff --git a/src/md.c b/src/md.c index 42438d59..05b04e24 100644 --- a/src/md.c +++ b/src/md.c @@ -86,111 +86,167 @@ void main_MD(SPARC_OBJ *pSPARC) { pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // For NPT_NP and NPH, a similar but slightly modified printing scheme is run, as the printing instances in this below setup is not compatible with NPT_NP and NPH ensemble, i.e. the printing setup in the below scheme (if condition) if used for NPT_NP and NPH would be corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies. So the quantities are not in-sync when being printed to 'log' or 'aimd' file, so this setup is done separately for NPT_NP and NPH with printing happening when all quantities are in-sync and belong to same time = t + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - fclose(output_md); - } + pSPARC->MDCount++; - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } - pSPARC->MDCount++; - pSPARC->elecgs_Count++; + fclose(output_md); + } - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); + #ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); + #endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,":MDSTEP: %d\n", Count); } - fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPT_NP_and_NPH(pSPARC, output_md, avgvel, maxvel, mindis); //The last four arguments: output_md, avgvel, maxvel and mindis are only passed so as to facilitate calling 'MD_QOI' or 'Print_fullMD' function from within NPT_NP or NPH subroutines - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - } + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); + #ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); + #endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } else { // Carry out the above procedure in slightly modified printing manner for NPT_NP and NPH ensemble + // File output_md stores all the desirable properties from a MD run + FILE *output_md, *output_fp; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); } - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop + // if(pSPARC->RestartFlag == 0){ + // fprintf(output_md,":MDSTEP: %d\n", 1); + // fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + // MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + // Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + // } + + fclose(output_md); + } + + pSPARC->MDCount++ + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount; // Count is the MD step no. to be performed + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); + #ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); + #endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,":MDSTEP: %d\n", Count); + } + + NPT_NP_and_NPH(pSPARC, output_md, avgvel, maxvel, mindis); + + // This is true, restart happens from the instance when position are at time = t, whereas momenta are lagging behind by dt/2, so they belong to time = t-dt/2 (unlike printing all quantities to an MD file, which happens when all quantities belong to time = t, and in-sync with each other) + if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + // pSPARC->MDCount ++; // This is incremented within 'NPT_NP_and_NPH_main' subroutine + Count ++; // This should not be moved to 'NPT_NP_and_NPH_main' subroutine + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + + } + + if(check2){ pSPARC->MDCount --; print_restart_typ = 1; @@ -1934,28 +1990,6 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ } pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } - - #ifdef DEBUG - if (rank == 0) { - printf("within init"); - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - } - } - #endif // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// //Initialize constraint stress to 0 @@ -2178,16 +2212,50 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->constraint_stress, 3); + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + // ------------------------------------- BEGIN: PRINTING FOR NPT_NP OR NPH ENSEMBLE (this marks the end of one timestep) --------------------------------------// // Obtain updated velocities in cartesian coordinates for use in MD_QOI function cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + + + int Count = pSPARC->MDCount + pSPARC->restartCount; int check1 = (pSPARC->PrintMDout == 1 && !rank); - MD_QOI(pSPARC, avgvel, maxvel, mindis); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + int check2 = (pSPARC->Printrestart == 1 && !rank); + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - pSPARC->t_md); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); + #ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - pSPARC->t_md)); + #endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - pSPARC->t_md)); + fclose(output_fp); + } + + //Increment MDCount by 1 (this marks the start of MDCount^{th} step ) + pSPARC->MDCount++; + // ------------------------------------- END: PRINTING FOR NPT_NP OR NPH ENSEMBLE (this marks the beginning of new timestep) --------------------------------------// + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// From 93b603614e14bd65b2f814a05dc7379f41286ff6 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Fri, 3 Apr 2026 12:49:24 -0400 Subject: [PATCH 50/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/md.c b/src/md.c index 05b04e24..56a85029 100644 --- a/src/md.c +++ b/src/md.c @@ -404,10 +404,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { } } - pSPARC->KE_save = 0.0; fetch_MD_cell_ingredients(pSPARC, false); - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 @@ -479,7 +476,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { //Calculate_ionic_stress(pSPARC); - //Ion vel fractional memory allocation already done within 'RestartMD' function as that is being MPI communicated + //Pm_ion memory allocation already done within 'RestartMD' function as that is being MPI communicated pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); if (pSPARC->ion_vel_fractional == NULL) { fprintf(stderr, "Error: Memory allocation failed for ionic fractional velocity array.\n"); @@ -1950,8 +1947,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ // Calculate kinetic energy and kinetic stress Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - pSPARC->KE_save = pSPARC->KE; - + // Calculating thermostat energies pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper @@ -2387,7 +2383,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma //Update kinetic energy and kinetic stress based on new S pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); - pSPARC->KE_save = pSPARC->KE; + for (int i = 0; i < 9; i++){ pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); } From 380123bf8be91b9d6cae7623b9a6defb0ea92736 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Fri, 3 Apr 2026 12:51:12 -0400 Subject: [PATCH 51/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/md.c b/src/md.c index 56a85029..9ed7852e 100644 --- a/src/md.c +++ b/src/md.c @@ -405,9 +405,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { } fetch_MD_cell_ingredients(pSPARC, false); - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->pressure_external /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->stress_external[i] /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 } pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; @@ -454,9 +454,9 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { //fetch_MD_cell_ingredients_restart(pSPARC); pSPARC->KE_save = 0.0; - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->pressure_external /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->stress_external[i] /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 }// transfer from GPa to Ha/Bohr^3 pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; @@ -3908,7 +3908,6 @@ void RestartMD(SPARC_OBJ *pSPARC) { } - /* @ brief: function to rename the restart file */ From 7f8d9416af43955b255c7cae3303b25eaedeca2d Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Fri, 3 Apr 2026 13:09:54 -0400 Subject: [PATCH 52/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 176 ++++++++++++------------------------------------------- 1 file changed, 37 insertions(+), 139 deletions(-) diff --git a/src/md.c b/src/md.c index 9ed7852e..9fe6beff 100644 --- a/src/md.c +++ b/src/md.c @@ -1449,8 +1449,8 @@ void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double * int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - + //MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); //Stress_i is never used in this ensemble + //Calculate initial hamitonian if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)){ NPT_NP_and_NPH_init_hamiltonian(pSPARC); @@ -1467,9 +1467,6 @@ void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double * Calculate_Properties(pSPARC); //Calculate_electronicGroundState(pSPARC); pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif } /* @@ -1490,119 +1487,6 @@ void transpose_and_add(double *matrix1){ matrix1[5] = matrix1[7] = s12; } -void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - int i, j, k; - - double TEMP_TOL = 1e-12; - // Construct LatUVec; - double mag; - for(i = 0; i < 3; i++){ - mag = sqrt(pow(pSPARC->full_lattice[3 * i], 2.0) - + pow(pSPARC->full_lattice[3 * i + 1], 2.0) - + pow(pSPARC->full_lattice[3 * i + 2], 2.0)); - pSPARC->LatUVec[3 * i] = pSPARC->full_lattice[3 * i]/mag; - pSPARC->LatUVec[3 * i + 1] = pSPARC->full_lattice[3 * i + 1]/mag; - pSPARC->LatUVec[3 * i + 2] = pSPARC->full_lattice[3 * i + 2]/mag; - } - - // determinant of 3x3 Jacobian - pSPARC->Jacbdet = 0.0; - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - if(i != j && j != k && k != i) - pSPARC->Jacbdet += ((i - j) * (j - k) * (k - i)/2) * pSPARC->LatUVec[3 * i] * pSPARC->LatUVec[3 * j + 1] * pSPARC->LatUVec[3 * k + 2]; - } - } - } - - if(pSPARC->Jacbdet <= 0){ - if(rank == 0) - printf("ERROR: Volume(det(jacobian)) %lf is <= 0\n", pSPARC->Jacbdet); - exit(EXIT_FAILURE); - } - - // transformation matrix for distance - for(i = 0; i < 9; i++) - pSPARC->metricT[i] = 0.0; - - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - pSPARC->metricT[3*i + j] += pSPARC->LatUVec[3*i + k] * pSPARC->LatUVec[3*j + k]; - } - } - } - - pSPARC->metricT[1] = 2 * pSPARC->metricT[1]; - pSPARC->metricT[2] = 2 * pSPARC->metricT[2]; - pSPARC->metricT[5] = 2 * pSPARC->metricT[5]; - - // transformation matrix for gradient - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - pSPARC->gradT[3*j + i] = (pSPARC->LatUVec[3 * ((j+1) % 3) + (i+1) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+2) % 3] - pSPARC->LatUVec[3 * ((j+1) % 3) + (i+2) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+1) % 3])/pSPARC->Jacbdet; - } - } - - // transformation matrix for laplacian - for(i = 0; i < 9; i++) - pSPARC->lapcT[i] = 0.0; - - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - pSPARC->lapcT[3*i + j] += pSPARC->gradT[3*i + k] * pSPARC->gradT[3*j + k]; - } - } - } - - /* Different cell types for laplacian */ - if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 11; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 12; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 13; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 14; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 15; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 16; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 17; -#ifdef DEBUG - if(!rank) - printf("\n\nCELL_TYP: %d\n\n",pSPARC->cell_typ); -#endif - /* transform the coefficiens of lapacian*/ - // int p, FDn = pSPARC->order/2; - // double dx_inv, dy_inv, dz_inv, dx2_inv, dy2_inv, dz2_inv; - // dx_inv = 1.0 / (pSPARC->delta_x); - // dy_inv = 1.0 / (pSPARC->delta_y); - // dz_inv = 1.0 / (pSPARC->delta_z); - // dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - // dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - // dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - // for (p = 0; p < FDn + 1; p++) { - // pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - // pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - // pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - // pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - // pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - // pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - // pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - // pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - // pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - // pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - // pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - // pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - // } - // TODO: Find maximum eigenvalue of Hamiltionian (= max. eigvalue of -0.5 lap) for non orthogonal periodic systems -} /* Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix @@ -1612,7 +1496,7 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double old_cell[9]; + double old_cell[9]; old_LatVec[9]; //Compute Cell lattice vectors (scaled by LATVEC scale) if (pSPARC->Flag_latvec_scale == 0){ @@ -1633,7 +1517,7 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ //Compute metric_tensor (G) in real-space (not reciprocal space) cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - if (pSPARC->Flag_latvec_scale == 1){ + if (pSPARC->Flag_latvec_scale == 1){ // for Flag_latvec_scale == 0, the update for 'range_x,y,z' has already happened within restart function pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); @@ -1646,10 +1530,18 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ pSPARC->initialLatVecLength[0] = 1; pSPARC->initialLatVecLength[1] = 1; pSPARC->initialLatVecLength[2] = 1; } - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat_MD(pSPARC); + //Assign full_lattice to LatVec for updating various quantities in 'Cart2nonCart_transformMat' + for (int i = 0; i < 9; i++){old_LatVec[i] = pSPARC->LatVec[i];} + for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = pSPARC->full_lattice[i];} + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT (this function updates all quantites based on 'LatVec' variable as input, but we actually want it based on 'full_lattice' variable, which contains all the cell lattice vectors updates, so we do the step above this to assign full_lattice to LatVec) + Cart2nonCart_transformMat(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + //Reassign LatVec it old values + for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = oldLatVec[i];} + + // printf("Volume cell %lf \n",pSPARC->volumeCell); // printf("range_x %lf \n",pSPARC->range_x); // printf("range_y %lf \n",pSPARC->range_y); @@ -1659,16 +1551,16 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ // printf("FUll lattice[%d] is %lf \n",i,pSPARC->full_lattice[i]); // } - if (pSPARC->Flag_latvec_scale == 1){ - for (int i = 0; i < 9; i++){ - printf("LatVec[%d] is %lf \n",i,pSPARC->LatVec[i]); - } - } - if (pSPARC->Flag_latvec_scale == 0){ - for (int i = 0; i < 9; i++){ - printf("LatUVec[%d] is %lf \n",i,pSPARC->LatUVec[i]); - } - } + // if (pSPARC->Flag_latvec_scale == 1){ + // for (int i = 0; i < 9; i++){ + // printf("LatVec[%d] is %lf \n",i,pSPARC->LatVec[i]); + // } + // } + // if (pSPARC->Flag_latvec_scale == 0){ + // for (int i = 0; i < 9; i++){ + // printf("LatUVec[%d] is %lf \n",i,pSPARC->LatUVec[i]); + // } + // } // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); @@ -1704,7 +1596,7 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); // Now computing reciprocal metric tensor, cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - printf("here"); + } void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ @@ -1827,7 +1719,7 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } } - //If updating the cell, then also calculate the velocity of cell lattice vectors (only useful in 1st MD step (start afresh or restart)) + //If updating the cell, then also calculate the velocity of cell lattice vectors (only useful in 1st MD step (if starting with nonzero lattice vector velocities: but as of now this step is not really useful, as we are by default only supporting zero initializing for lattice vector velocities)) else { double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; @@ -1987,11 +1879,6 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// - - //Initialize constraint stress to 0 - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; - } } /* @@ -2029,6 +1916,12 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } double baro_const3 = 1.0 / baro_const1; + if (pSPARC->MDCount == 1){ + //Initialize constraint stress to 0 + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; + } + } // printf("QMASS: %lf\n",pSPARC->NPT_NP_qmass); // printf("SNOSE[0] %lf \n",pSPARC->SNOSE[0]); // printf("SNOSE[1] %lf \n",pSPARC->SNOSE[1]); @@ -2095,6 +1988,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma if (pSPARC->NPT_NP_ANGLES == 0){ compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); } + } else { if (pSPARC->NPH_ANGLES == 0){ @@ -2217,6 +2111,10 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount); + #endif int Count = pSPARC->MDCount + pSPARC->restartCount; int check1 = (pSPARC->PrintMDout == 1 && !rank); int check2 = (pSPARC->Printrestart == 1 && !rank); From 3249051c74244fac78fe3130eb03434d739700e8 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Fri, 3 Apr 2026 13:27:06 -0400 Subject: [PATCH 53/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/md.c b/src/md.c index 9fe6beff..b2f5ed90 100644 --- a/src/md.c +++ b/src/md.c @@ -592,7 +592,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { #ifdef DEBUG // Statistics to be set to zero initially - if (pSPARC->RestartFlag == 0){ + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; @@ -600,7 +600,7 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->mean_total_internal_stress[i] = 0.0; pSPARC->std_total_internal_stress[i] = 0.0; } - } + #endif } @@ -2784,7 +2784,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); else fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); } if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ @@ -2792,10 +2792,10 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 \n"); if (pSPARC->Flag_latvec_scale == 0){ fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = 1 \n",pSPARC->MDMeth); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = 1 \n"); } else { fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n"); } if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); @@ -2808,14 +2808,16 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell expansion). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated as: kinetic_stress (positive convention) - electronic stress - constraint stress; as per (E. Hernandez, 2001) paper + fprintf(output_md,":Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated as: kinetic_stress (positive convention) - electronic stress - constraint stress; as per (E. Hernandez, 2001) paper } } if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_TOTSTRESS: Total internal pressure (also accounting pressure due to any constraint on cell expansion). Unit=GPa \n"); + fprintf(output_md,":Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa \n"); + fprintf(output_md,":Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa \n"); } fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" " where N = number of particles, k = Boltzmann constant, V = volume\n"); @@ -2847,13 +2849,13 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); } if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH); + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH / pSPARC->n_atom); if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); //This is full hamiltonian, not per atom as this is what should be measured to ensure conservation fprintf(output_md,":SNOSE[0]:%18.10E \n", pSPARC->SNOSE[0]); fprintf(output_md,":SNOSE[1]:%18.10E \n", pSPARC->SNOSE[1]); } if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); //This is full hamiltonian, not per atom as this is what should be measured to ensure conservation // Print atomic position if(pSPARC->PrintAtomPosFlag){ @@ -2880,6 +2882,13 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ fprintf(output_md,":ANGLES:\n"); fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); @@ -2914,7 +2923,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } else{ //Trigger NPT_NP or NPH ensemble stress printing - fprintf(output_md,":STRIO:\n"); + fprintf(output_md,":STRIO:\n"); //Ion-kinetic stress double temp_stress[6]; temp_stress[0] = pSPARC->kinetic_stress[0]; temp_stress[1] = pSPARC->kinetic_stress[1]; temp_stress[2] = pSPARC->kinetic_stress[2]; temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[8]; @@ -2924,7 +2933,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma for (int i = 0; i < 6; i++) stress_e[i] = pSPARC->stress[i]; // stress_i or ionic stress function is never called in NPT_NP or NPH ensemble, so pSPARC->stress does not include contribution from it, and thus no need to subtract stress_i from pSPARC->stress, as done in other ensembles PrintStress (pSPARC, stress_e, output_md); - fprintf(output_md,":CONSTRESS:\n"); + fprintf(output_md,":CONSTRESS:\n"); //Constraint stress temp_stress[0] = pSPARC->constraint_stress[0]; temp_stress[1] = pSPARC->constraint_stress[1]; temp_stress[2] = pSPARC->constraint_stress[2]; temp_stress[3] = pSPARC->constraint_stress[4]; temp_stress[4] = pSPARC->constraint_stress[5]; temp_stress[5] = pSPARC->constraint_stress[8]; PrintStress (pSPARC, temp_stress, output_md); @@ -2970,12 +2979,12 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // Print Statistical properties fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":PREST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":MEAN_TOTSTRESS:\n"); + fprintf(output_md,":PRESST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":MEAN_TOTSTREST:\n"); fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->mean_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[2] * CONST_HA_BOHR3_GPA , pSPARC->mean_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[5] * CONST_HA_BOHR3_GPA , pSPARC->mean_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[8] * CONST_HA_BOHR3_GPA); - fprintf(output_md,":STD_TOTSTRESS:\n"); + fprintf(output_md,":STD_TOTSTREST:\n"); fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->std_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[2] * CONST_HA_BOHR3_GPA , pSPARC->std_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[5] * CONST_HA_BOHR3_GPA , pSPARC->std_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[8] * CONST_HA_BOHR3_GPA); From 3731e3f2e2975fa1c60cf79713ffa0dc0fe76fe7 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Fri, 3 Apr 2026 13:37:27 -0400 Subject: [PATCH 54/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/md.c b/src/md.c index b2f5ed90..eeeb12d9 100644 --- a/src/md.c +++ b/src/md.c @@ -1607,14 +1607,10 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + for (int i = 0; i < 3; i++) { + pSPARC->full_lattice[i] = pSPARC->LatUVec[i] * pSPARC->range_x; + pSPARC->full_lattice[i+3] = pSPARC->LatUVec[i + 3] * pSPARC->range_y; + pSPARC->full_lattice[i+6] = pSPARC->LatUVec[i + 6] * pSPARC->range_z; } //Compute metric_tensor (G) in real-space (not reciprocal space) @@ -1653,18 +1649,21 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat_MD(pSPARC); + //Assign full_lattice to LatVec for updating various quantities in 'Cart2nonCart_transformMat' + for (int i = 0; i < 9; i++){old_LatVec[i] = pSPARC->LatVec[i];} + for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = pSPARC->full_lattice[i];} + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT (this function updates all quantites based on 'LatVec' variable as input, but we actually want it based on 'full_lattice' variable, which contains all the cell lattice vectors updates, so we do the step above this to assign full_lattice to LatVec) + Cart2nonCart_transformMat(pSPARC); pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + //Reassign LatVec it old values + for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = oldLatVec[i];} + + // Update/Calculate new angles between lattice vectors + pSPARC->angle_12 = acos( pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y) ) * 180 / M_PI; + pSPARC->angle_13 = acos( pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z) ) * 180 / M_PI; + pSPARC->angle_23 = acos( pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z) ) * 180 / M_PI; //Update LATVEC_SCALE and LatVec if (pSPARC->Flag_latvec_scale == 1){ @@ -2110,8 +2109,6 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // Obtain updated velocities in cartesian coordinates for use in MD_QOI function cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); - - #ifdef DEBUG if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount); #endif @@ -2980,11 +2977,11 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); fprintf(output_md,":PRESST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":MEAN_TOTSTREST:\n"); + fprintf(output_md,":MEAN_TOTSTRESS:\n"); fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->mean_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[2] * CONST_HA_BOHR3_GPA , pSPARC->mean_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[5] * CONST_HA_BOHR3_GPA , pSPARC->mean_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[8] * CONST_HA_BOHR3_GPA); - fprintf(output_md,":STD_TOTSTREST:\n"); + fprintf(output_md,":STD_TOTSTRESS:\n"); fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->std_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[2] * CONST_HA_BOHR3_GPA , pSPARC->std_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[5] * CONST_HA_BOHR3_GPA , pSPARC->std_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[8] * CONST_HA_BOHR3_GPA); @@ -3802,9 +3799,10 @@ void RestartMD(SPARC_OBJ *pSPARC) { } if(pSPARC->RestartFlag == 1) { pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0)) { // For NPT_NP and NPH the 'reinitialize_mesh_NPT' function is being called from 'fetch_MD_cell_ingredients_restart' after calculating new Jacbdet, cell volume etc - reinitialize_mesh_NPT(pSPARC); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0)) { + reinitialize_mesh_NPT(pSPARC); } + // For NPT_NP and NPH the 'reinitialize_mesh_NPT' function is being called from 'fetch_MD_cell_ingredients_restart' after calculating new Jacbdet, cell volume etc if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)||(strcmpi(pSPARC->MDMeth,"NPH") == 0) ){ fetch_MD_cell_ingredients_restart(pSPARC); //Now reinitialize mesh based on calculated Jacbdet and other ingredients From 20a993a0a20a3a17fa0a9384925190304486bc78 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Fri, 3 Apr 2026 16:19:27 -0400 Subject: [PATCH 55/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/MD_copy1.c | 3861 ++++++++++++++++++++++++++++++++++++++++++ src/include/isddft.h | 2 +- src/include/md.h | 6 +- src/md.c | 179 +- 4 files changed, 3975 insertions(+), 73 deletions(-) create mode 100644 src/MD_copy1.c diff --git a/src/MD_copy1.c b/src/MD_copy1.c new file mode 100644 index 00000000..0d7c63c8 --- /dev/null +++ b/src/MD_copy1.c @@ -0,0 +1,3861 @@ +/** + * @file md.c + * @brief This file contains the functions for performing molecular dynamics. + * + * @author Phanish Suryanarayana + * Abhiraj Sharma + * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. + */ + +#include +#include +#include +#include +#include +#include +#ifdef USE_MKL + #include +#else + #include + #include +#endif + +#include "md.h" +#include "isddft.h" +#include "orbitalElecDensInit.h" +#include "initialization.h" +#include "electronicGroundState.h" +#include "stress.h" +#include "tools.h" +#include "pressure.h" +#include "relax.h" +#include "electrostatics.h" +#include "readfiles.h" +#include "eigenSolver.h" // Mesh2ChebDegree +#include "readfiles.h" +#include "sparc_mlff_interface.h" + +#define max(a,b) ((a)>(b)?(a):(b)) + +//TODO: Implement the case when some atom coordinates are held fixed +/** + @ brief: Main function of MD +**/ +void main_MD(SPARC_OBJ *pSPARC) { + int rank; + int print_restart_typ = 0; + double t_init, t_acc, *avgvel, *maxvel, *mindis; + t_init = MPI_Wtime(); + pSPARC->t_md = MPI_Wtime(); + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); + + // Check whether the restart has to be performed + if(pSPARC->RestartFlag != 0){ + // Check if .restart file present + if(rank == 0){ + FILE *rst_fp = NULL; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + + if(rst_fp == NULL) + pSPARC->RestartFlag = 0; + } + MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (pSPARC->RestartFlag != 0) { + RestartMD(pSPARC); + int atm; + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); + } + } + } + } + + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + Initialize_MD(pSPARC); + + + pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + + if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // For NPT_NP and NPH, a similar but slightly modified printing scheme is run, as the printing instances in this below setup is not compatible with NPT_NP and NPH ensemble, i.e. the printing setup in the below scheme (if condition) if used for NPT_NP and NPH would be corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies. So the quantities are not in-sync when being printed to 'log' or 'aimd' file, so this setup is done separately for NPT_NP and NPH with printing happening when all quantities are in-sync and belong to same time = t + FILE *output_md, *output_fp; + // File output_md stores all the desirable properties from a MD run + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + if(pSPARC->RestartFlag == 0){ + fprintf(output_md,":MDSTEP: %d\n", 1); + fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + } + + fclose(output_md); + } + + if (!rank && pSPARC->MD_Nstep > 0) { + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); + #ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); + #endif + if (check1){ + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,":MDSTEP: %d\n", Count); + } + + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) + NVT_NH(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) + NVE(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) + NVK_G(pSPARC); + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + NPT_NH(pSPARC); + else{ + if (!rank){ + printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); + } + exit(EXIT_FAILURE); + } + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + + if(check1) { + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + if(check1) + fclose(output_md); + #ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); + #endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); + fclose(output_fp); + } + + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + + } else { // Carry out the above procedure in slightly modified printing manner for NPT_NP and NPH ensemble + // File output_md stores all the desirable properties from a MD run + FILE *output_md; + + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ + output_md = fopen(pSPARC->MDFilename,"w"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + pSPARC->MDCount = -1; + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + pSPARC->MDCount++; + + // if(pSPARC->RestartFlag == 0){ + // fprintf(output_md,":MDSTEP: %d\n", 1); + // fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); + // MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + // Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file + // } + + fclose(output_md); + } + + pSPARC->MDCount++; + pSPARC->elecgs_Count++; + + // Perform MD until maxStep is reached or total walltime is hit + int Count = pSPARC->MDCount + pSPARC->restartCount; // Count is the MD step no. to be performed + #ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); + #endif + + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes + while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ + t_init = MPI_Wtime(); + + NPT_NP_and_NPH(pSPARC, avgvel, maxvel, mindis); + + // This is true, restart happens from the instance when position are at time = t, whereas momenta are lagging behind by dt/2, so they belong to time = t-dt/2 (unlike printing all quantities to an MD file, which happens when all quantities belong to time = t, and in-sync with each other) + if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written + PrintMD(pSPARC, 1, print_restart_typ); + + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + pSPARC->MDCount ++; + Count ++; + t_acc += (MPI_Wtime() - t_init)/60; + } // end while loop + + } + + + if(check2){ + pSPARC->MDCount --; + print_restart_typ = 1; + PrintMD(pSPARC, 1, print_restart_typ); + } + free(avgvel); + free(maxvel); + free(mindis); + if (rank == 0 && pSPARC->fp_energy != NULL) { + fclose(pSPARC->fp_energy); + pSPARC->fp_energy = NULL; + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ + free(pSPARC->ion_vel_fractional); + free(pSPARC->Pm_ion); + } +} + +/** + @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) + **/ +void Initialize_MD(SPARC_OBJ *pSPARC) { + int ityp, atm, count, rand_seed = 5; + + if (pSPARC->ion_vel_dstr_rand == 1) { + // add a time-dependent component to the seed + rand_seed += (int)MPI_Wtime(); + } + + pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_accel == NULL) { + printf("\nCannot allocate memory for ion acceleration array!\n"); + exit(EXIT_FAILURE); + } + + int count_x = 0; + int count_y = 0; + int count_z = 0; + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++) { + count_x += pSPARC->mvAtmConstraint[3 * count]; + count_y += pSPARC->mvAtmConstraint[3 * count + 1]; + count_z += pSPARC->mvAtmConstraint[3 * count + 2]; + count++; + } + pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) + + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value + + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) + pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units + + pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units + + // Variables for NVT_NH + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ + pSPARC->snose = 0.0; + pSPARC->xi_nose = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + } + // Variables for NPT_NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ + int i; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { + if (!rank) { + printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); + printf("Example as below\n"); + printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); + exit(EXIT_FAILURE); + } + } + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ + printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); + exit(EXIT_FAILURE); + } + } + if(pSPARC->NPT_NHbmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + pSPARC->vlogs[i] = 0.0; + pSPARC->xlogs[i] = 0.0; + } + pSPARC->vlogv = 0.0; + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + pSPARC->scale = 1.0; + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart + if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; + else pSPARC->NPTisotropicFlag = 0; + int i; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->glogs[i] = 0.0; + } + // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time + // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file + pSPARC->thermos_T = pSPARC->thermos_Ti; + pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 + + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + Calculate_ionic_stress(pSPARC); + } + // Variables for NPT_NP and NPH + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) && pSPARC->RestartFlag != 1){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + if (pSPARC->Flag_latvec_scale == 1){ + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + } + else{ + pSPARC->initialLatVecLength[0] = 1; pSPARC->initialLatVecLength[1] = 1; pSPARC->initialLatVecLength[2] = 1; + } + + pSPARC->maxTimeIter = 100; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if(pSPARC->NPT_NP_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + if(pSPARC->NPH_bmass == 0.0) { + if (!rank) { + printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); + exit(EXIT_FAILURE); + } + } + } + + fetch_MD_cell_ingredients(pSPARC, false); + pSPARC->pressure_external /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 + } + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ + if (!rank) { + printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); + exit(EXIT_FAILURE); + } + } + + if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH + if (!rank) { + printf("Mass of thermostat variable is zero in NPH ensemble\n"); + } + } + + pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) + pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) + + pSPARC->thermos_Ti = pSPARC->ion_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; + + pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); + exit(EXIT_FAILURE); + } + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); + exit(EXIT_FAILURE); + } + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->maxTimeIter = 100; + + //fetch_MD_cell_ingredients_restart(pSPARC); + pSPARC->KE_save = 0.0; + + pSPARC->pressure_external /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 + for (int i = 0; i < 6; i++){ + pSPARC->stress_external[i] /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 + }// transfer from GPa to Ha/Bohr^3 + pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; + pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; + pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + + + if(strcmpi(pSPARC->MDMeth,"NPH")==0){ + pSPARC->NPT_NP_qmass = 0; + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + } + // pSPARC->thermos_Ti = pSPARC->elec_T; + pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! + + //Calculate_ionic_stress(pSPARC); + + //Pm_ion memory allocation already done within 'RestartMD' function as that is being MPI communicated + pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic fractional velocity array.\n"); + exit(EXIT_FAILURE); + } + } + + if(pSPARC->RestartFlag == 0){ + double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; + mvsum_x = mvsum_y = mvsum_z = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; + } + if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + } + // Uniform velocity distribution + if(pSPARC->ion_vel_dstr == 1){ + double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu + vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + while(s>1.0){ + x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 + y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; + s = x * x + y * y; + } + pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); + s = 2.0 * sqrt(1.0 - s); + pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; + pSPARC->ion_vel[count * 3] = s * x * vel_cm; + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) + { + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); + pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); + mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; + mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; + mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; + count += 1; + } + } + } + + // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; + pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; + pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; + count += 1; + } + } + + // Zeroing the velocity for fixed atoms + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; + pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + + // Rescale velocities + double rescal_fac ; + rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; + pSPARC->KE = 0.0; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; + pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count += 1; + } + } + } + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + count += 1; + } + } + +#ifdef DEBUG + // Statistics to be set to zero initially + + pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; + pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; + pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; + for (int i = 0; i < 9; i++){ + pSPARC->mean_total_internal_stress[i] = 0.0; + pSPARC->std_total_internal_stress[i] = 0.0; + } + +#endif +} + +/* +@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) +*/ +void NVT_NH(SPARC_OBJ *pSPARC) { + double fsnose; + // First step velocity Verlet + VVerlet1(pSPARC); + // Update thermostat + pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); + fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; + pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); + pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Second step velocity Verlet + VVerlet2(pSPARC); +} + +/* +@ brief: function to perform first step of velocity verlet algorithm +*/ +void VVerlet1(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } +} + +/* +@ brief: function to perform second step of velocity verlet algorithm +*/ +void VVerlet2(SPARC_OBJ* pSPARC) { + int ityp, atm, count = 0, ready = 0, kk, jj; + double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; + vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + xin_nose = pSPARC->xi_nose; + pSPARC->v2nose = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + //a(t+dt) = F(t+dt)/M + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; + vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; + vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; + count ++; + } + } + do { + xio = xin_nose ; + delxi = 0.0 ; + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vonose[count * 3] = vel_temp[count * 3] ; + vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; + vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; + hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); + hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); + hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); + binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3] * binose[count * 3] ; + binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; + binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; + delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; + count ++; + } + } + dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; + delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; + delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; + pSPARC->v2nose = 0.0 ; + count = 0 ; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; + vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; + vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; + pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); + count ++; + } + } + xin_nose = xio + delxi ; + ready = 1 ; + //Test for convergence + kk = -1, jj = 0; + do{ + kk = kk + 1 ; + if(kk >= pSPARC->n_atom){ + kk = 0; + jj ++; + } + if(kk < pSPARC->n_atom && jj < 3){ + //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) + // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; + if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) + ready = 0 ; + } + else{ + //if (fabs(xin_nose) < 1e-50) + // xin_nose = 1e-50 ; + if(fabs((xin_nose - xio)/xin_nose) > 1e-7) + ready = 0 ; + } + } while(kk < pSPARC->n_atom && jj < 3 && ready); + } while (ready == 0); + + pSPARC->xi_nose = xin_nose ; + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; + pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + free(vel_temp); + free(vonose); + free(binose); + free(hnose); +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. + **/ +void NVE(SPARC_OBJ *pSPARC) { + // Leapfrog step - 1 + Leapfrog_part1(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + // Leapfrog step (part-2) + Leapfrog_part2(pSPARC); +} + +/* +@ brief: function to update position of atoms using Leapfrog method +*/ +void Leapfrog_part1(SPARC_OBJ *pSPARC) { + /******************************************************** + // Leapfrog algorithm + PART-I (Implemented in this function) + v_(t+dt/2) = v_t + 0.5*dt*a_t + r_(t+dt) = r_t + dt*v_(t+dt/2) + + PART-II (Implemented in the next function, after computing + a_(t+dt) for current positions) + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + **********************************************************/ + int count = 0, atm; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + // v_(t+dt/2) = v_t + 0.5*dt*a_t + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + // r_(t+dt) = r_t + dt*v_(t+dt/2) + pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; + count ++; + } +} + +/* + @ brief: function to update velocity of atoms using Leapfrog method +*/ +void Leapfrog_part2(SPARC_OBJ *pSPARC) { + /************************************ + PART-II Leapfrog algorithm + v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) + *************************************/ + int count = 0, ityp, atm; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + +} + +/** + @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. + It is based on the implementation in ABINIT (ionmov=12) + **/ +void NVK_G(SPARC_OBJ *pSPARC) { + // Calculate velocity at next half time step + Calc_vel1_G(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPSPARC); + pSPARC->elecgs_Count++; + + // Calculate velocity at next full time step + Calc_vel2_G(pSPARC); +} + + +/* + @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel1_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + + pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; + pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; + count ++; + } + } +} + + +/* + @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat +*/ + +void Calc_vel2_G(SPARC_OBJ *pSPARC) { + double v2gauss = 0.0; + double a = 0.0; + double b = 0.0; + int ityp, atm, count = 0; + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + + v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; + + a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; + + b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + + pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + + pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; + + count ++; + } + } + + a /= v2gauss; + b /= v2gauss; + + double sqb = sqrt(b); + double as = sqb * pSPARC->MD_dt/2.0; + if(as > 300.0) + as = 300.0; + + double s1 = cosh(as); + double s2 = sinh(as); + double s = a * (s1-1.0)/b + s2/sqb; + double scdot = a * s2/sqb + s1; + + count = 0; + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; + pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; + pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } +} + +/* +@ brief function to perform NPT MD simulation with Nose hoover chain. +wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) +reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). +Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 +Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). +A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. +Journal of Physics A: Mathematical and General, 39(19), 5629. +*/ +void NPT_NH (SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { + // Update velocity of particles in the second half timestep + AccelVelocityParticle(pSPARC); + // Update velocity of virtual thermo and baro variables in the second half timestep + IsoPress(pSPARC); + } + + // Update velocity of virtual thermo and baro variables in the first half timestep + IsoPress(pSPARC); + // Update velocity of particles in the first half timestep + AccelVelocityParticle(pSPARC); + // Update position of particles and size of cell in the timestep + PositionParticleCell(pSPARC); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; + #ifdef DEBUG + // Calculate Hamiltonian of the system. + hamiltonian_NPT_NH(pSPARC); + if (rank == 0){ + printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); + } + #endif + +} + +/* +@ brief function to update accelerations and velocities of particles changed by forces in NPT +*/ +void AccelVelocityParticle (SPARC_OBJ *pSPARC) { + int ityp, atm, count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; + pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; + pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; + pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; + pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; + count ++; + } + } +} + + +/* +@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT +*/ +void IsoPress(SPARC_OBJ *pSPARC) { + int i, atm, ityp; + int count = 0; + double scale, gn1kt, odnf, modnf, ktemp; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + pSPARC->KE = 0.0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); + count ++; + } + } + + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + scale = 1.0; + ktemp = pSPARC->kB * pSPARC->thermos_T; + gn1kt = (double)(pSPARC->dof + 1) * ktemp; + + modnf = 3.0/(double)pSPARC->dof; + odnf = 1.0 + 3.0/(double)pSPARC->dof; + // update accelerations of the virtual variables, 1st + double glogv = 0.0; + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + + // update velocities of the virtual variables, 1st + double alocal; + double nowvlogv = pSPARC->vlogv; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of baro variable, 2nd + alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); + scale = scale * alocal; + pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); + glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; + // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); + // update thermostat position, for computing Hamiltonian + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; + } + // update velocities of the baro variables, 2nd + nowvlogv += pSPARC->MD_dt / 4.0 * glogv; + // update accelerations of thermal variable, 2nd + pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; + for (i = 0; i < pSPARC->NPT_NHnnos; i++) { + pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; + } + for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { + pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; + } + pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; + // update velocities of particles + count = 0; + for (atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->ion_vel[count * 3] *= scale; + pSPARC->ion_vel[count * 3 + 1] *= scale; + pSPARC->ion_vel[count * 3 + 2] *= scale; + count ++; + } + // send calculated variables back to pSPARC + pSPARC->vlogv = nowvlogv; + #ifdef DEBUG + if (rank == 0){ + printf("rank %d", rank); + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); + } + printf("\nglogv is %12.9f\n", glogv); + printf("\nvlogv is %12.9f\n", nowvlogv); + } + #endif +} + +/* +@ brief function to update positions of particles and size of a cell in NPT +*/ +void PositionParticleCell(SPARC_OBJ *pSPARC) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // update particle positions + if (pSPARC->NPTisotropicFlag == 1) { + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; + pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); + pSPARC->range_x *= pSPARC->scale; + pSPARC->range_y *= pSPARC->scale; + pSPARC->range_z *= pSPARC->scale; + } + else { // only 1 or 2 lattice vectors can be rescaled + int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; + double rescale = 3.0/(double)dim; + + int count, atm; + double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; + mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); + mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); + + polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; + mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; + + double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; + double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate + double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity + count = 0; + for(atm = 0; atm < pSPARC->n_atom; atm++){ + carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; + carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; + + Cart2nonCart(gradT, carCoord, nonCarCoord); + Cart2nonCart(gradT, carVelo, nonCarVelo); + + if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; + else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; + else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; + + if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; + else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; + + nonCart2Cart(LatUVec, carCoord, nonCarCoord); + + pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; + count ++; + } + // update size of cell + pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; + if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; + } + #ifdef DEBUG + if(rank == 0){ + printf("rank %d", rank); + printf("scale of cell is %12.9f\n", pSPARC->scale); + printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + } + #endif +} + +/** + * @brief Write the re-initialized parameters into the output file. + */ +void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { + int nproc; + MPI_Comm_size(MPI_COMM_WORLD, &nproc); + + FILE *output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialized parameters \n"); + fprintf(output_fp,"***************************************************************************\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + else + fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); + fprintf(output_fp,"***************************************************************************\n"); + fprintf(output_fp," Reinitialization \n"); + fprintf(output_fp,"***************************************************************************\n"); + if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) + && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { + fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); + } else { + fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); + fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); + fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); + } + + fclose(output_fp); +} + +/* +@ brief reinitialize related variables after the size changing of cell. +*/ +void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + +#ifdef DEBUG + double t1, t2; +#endif + + int p, i; + // scaling factor + double scal = pSPARC->scale; // the ratio between length +#ifdef DEBUG + if(rank == 0){ + printf("scal: %12.6f\n", scal); + } +#endif + + pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); + pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); + pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); + + + pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; + +#ifdef DEBUG + if (!rank) { + // printf("Volume: %12.6f\n", vol); + printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + printf("COORD : \n"); + for (i = 0; i < 3 * pSPARC->n_atom; i++) { + printf("%12.6f\t",pSPARC->atom_pos[i]); + if (i%3==2 && i>0) printf("\n"); + } + printf("\n"); + } +#endif + + int FDn = pSPARC->order / 2; + + // 1st derivative weights including mesh + double dx_inv, dy_inv, dz_inv; + dx_inv = 1.0 / pSPARC->delta_x; + dy_inv = 1.0 / pSPARC->delta_y; + dz_inv = 1.0 / pSPARC->delta_z; + for (p = 1; p < FDn + 1; p++) { + pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; + pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; + pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; + } + + // 2nd derivative weights including mesh + double dx2_inv, dy2_inv, dz2_inv; + dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); + dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); + dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); + + // Stencil coefficients for mixed derivatives + if (pSPARC->cell_typ == 0) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; + } + } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { + for (p = 0; p < FDn + 1; p++) { + pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; + pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; + pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; + pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) + pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) + pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) + pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) + pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) + pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) + pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) + } + } + + // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) + if(pSPARC->cell_typ == 0) { +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] + + pSPARC->D2_stencil_coeffs_y[0] + + pSPARC->D2_stencil_coeffs_z[0]; + double scal_x, scal_y, scal_z; + scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; + scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; + scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; + for (int p = 1; p < FDn + 1; p++) { + pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) + + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) + + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); + } + pSPARC->MaxEigVal_mhalfLap *= -0.5; +#ifdef DEBUG + t2 = MPI_Wtime(); + if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", + pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); +#endif + } + + double h_eff = 0.0; + if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && + fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { + h_eff = pSPARC->delta_x; + } else { + // find effective mesh s.t. it has same spectral width + h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); + } + + // find Chebyshev polynomial degree based on max eigenvalue (spectral width) + if (pSPARC->ChebDegree < 0) { + pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); +#ifdef DEBUG + if (!rank && h_eff < 0.1) { + printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); + } + if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); +#endif + } else { +#ifdef DEBUG + if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); +#endif + } + + // default Kerker tolerance + if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user + pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; + } + + + // re-calculate k-point grid + Calculate_kpoints(pSPARC); + + // re-calculate local k-points array + if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { + if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { + Calculate_local_kpoints(pSPARC); + } + } + +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // re-calculate pseudocharge density cutoff ("rb") + Calculate_PseudochargeCutoff(pSPARC); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); +#endif + + + // write reinitialized parameters into output file + if (rank == 0) { + write_output_reinit_NPT(pSPARC); + } + +} + + +/* +@ brief: calculate Hamiltonian of the NPT system. +*/ +void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ + double kineticBaro, kineticTher, potentialBaro, potentialTher; + double hamiltonian; + int i; + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + + hamiltonian = pSPARC->KE + pSPARC->Etot; + kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; + kineticTher = 0.0; + for (i = 0; i < pSPARC->NPT_NHnnos; i++){ + kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; + } + double ktemp; + pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + ktemp = pSPARC->kB * pSPARC->thermos_T; + potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; + potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; + for (i = 1; i < pSPARC->NPT_NHnnos; i++){ + potentialTher += ktemp * pSPARC->xlogs[i]; + } + hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; + pSPARC->Hamiltonian_NPT_NH = hamiltonian; + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); + printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); + printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); + printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); + } +} + + + +/* +@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant. +Also performs NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant. NPH in this scheme is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference for NPT_NP and NPH: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. +Additional Reference for NPH: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." +Physical Review B 55.14 (1997): 8733. +*/ +void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + //Calculate initial hamitonian + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)){ + NPT_NP_and_NPH_init_hamiltonian(pSPARC); + } + //NPT_NPH_main routine + NPT_NPH_main(pSPARC, avgvel, maxvel, mindis); + // Reinitialize mesh size and related variables after changing size of cell + reinitialize_mesh_NPT(pSPARC); + // Charge extrapolation (for better rho_guess) + elecDensExtrapolation(pSPARC); + // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain + Check_atomlocation(pSPARC); + // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem + Calculate_Properties(pSPARC); + //Calculate_electronicGroundState(pSPARC); + pSPARC->elecgs_Count++; +} + +/* +Computes transpose of a matrix and adds it to the original matrix +*/ +void transpose_and_add(double *matrix1){ + //performs matrix1 = matrix1 + transpose(matrix1) + // Diagonals: m[i][i] = m[i][i] + m[i][i] + matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; + + // Off-diagonals: sum then assign to both sides + double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) + double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) + double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) + + matrix1[1] = matrix1[3] = s01; + matrix1[2] = matrix1[6] = s02; + matrix1[5] = matrix1[7] = s12; +} + + +/* +Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +*/ + +void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double oldLatVec[9]; + + //Compute Cell lattice vectors (scaled by LATVEC scale) + if (pSPARC->Flag_latvec_scale == 0){ + for (int i = 0; i < 3; i++) { + pSPARC->full_lattice[i] = pSPARC->LatUVec[i] * pSPARC->range_x; + pSPARC->full_lattice[i+3] = pSPARC->LatUVec[i + 3] * pSPARC->range_y; + pSPARC->full_lattice[i+6] = pSPARC->LatUVec[i + 6] * pSPARC->range_z; + } + } + else{ + for (int i = 0; i < 3; i++) { + pSPARC->full_lattice[i] = pSPARC->LatVec[i] * pSPARC->latvec_scale_x; + pSPARC->full_lattice[i+3] = pSPARC->LatVec[i+3] * pSPARC->latvec_scale_y; + pSPARC->full_lattice[i+6] = pSPARC->LatVec[i+6] * pSPARC->latvec_scale_z; + } + + } + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + if (pSPARC->Flag_latvec_scale == 1){ // for Flag_latvec_scale == 0, the update for 'range_x,y,z' has already happened within restart function + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); + } + else{ + pSPARC->initialLatVecLength[0] = 1; pSPARC->initialLatVecLength[1] = 1; pSPARC->initialLatVecLength[2] = 1; + } + + //Assign full_lattice to LatVec for updating various quantities in 'Cart2nonCart_transformMat' + for (int i = 0; i < 9; i++){oldLatVec[i] = pSPARC->LatVec[i];} + for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = pSPARC->full_lattice[i];} + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT (this function updates all quantites based on 'LatVec' variable as input, but we actually want it based on 'full_lattice' variable, which contains all the cell lattice vectors updates, so we do the step above this to assign full_lattice to LatVec) + Cart2nonCart_transformMat(pSPARC); + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + //Reassign LatVec it old values + for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = oldLatVec[i];} + + + // printf("Volume cell %lf \n",pSPARC->volumeCell); + // printf("range_x %lf \n",pSPARC->range_x); + // printf("range_y %lf \n",pSPARC->range_y); + // printf("range_z %lf \n",pSPARC->range_z); + + // for (int i = 0; i < 9; i++){ + // printf("FUll lattice[%d] is %lf \n",i,pSPARC->full_lattice[i]); + // } + + // if (pSPARC->Flag_latvec_scale == 1){ + // for (int i = 0; i < 9; i++){ + // printf("LatVec[%d] is %lf \n",i,pSPARC->LatVec[i]); + // } + // } + // if (pSPARC->Flag_latvec_scale == 0){ + // for (int i = 0; i < 9; i++){ + // printf("LatUVec[%d] is %lf \n",i,pSPARC->LatUVec[i]); + // } + // } + + // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) + double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); + double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); + double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); + + pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; + pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; + pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; + + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + +} + +void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double old_cell[9]; double new_cell[9]; + + if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD + + for (int i = 0; i < 3; i++) { + pSPARC->full_lattice[i] = pSPARC->LatUVec[i] * pSPARC->range_x; + pSPARC->full_lattice[i+3] = pSPARC->LatUVec[i + 3] * pSPARC->range_y; + pSPARC->full_lattice[i+6] = pSPARC->LatUVec[i + 6] * pSPARC->range_z; + } + + //Compute metric_tensor (G) in real-space (not reciprocal space) + cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); + + // Cosine of Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + + pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; + pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; + pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; + + } + + // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) + new_cell[0] = sqrt(pSPARC->metric_tensor[0]); + new_cell[1] = 0; + new_cell[2] = 0; + + new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); + new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); + new_cell[5] = 0; + + new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); + new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); + new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); + + if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). + //Update full cell's lattice vectors + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); + + //Update range_x, range_y, range_z, volumeCell, + pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); + pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); + pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); + + //Assign full_lattice to LatVec for updating various quantities in 'Cart2nonCart_transformMat' + double oldLatVec[9]; + for (int i = 0; i < 9; i++){oldLatVec[i] = pSPARC->LatVec[i];} + for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = pSPARC->full_lattice[i];} + + //Update LatUVec, Jacbdet, metricT, gradT, lapcT (this function updates all quantites based on 'LatVec' variable as input, but we actually want it based on 'full_lattice' variable, which contains all the cell lattice vectors updates, so we do the step above this to assign full_lattice to LatVec) + Cart2nonCart_transformMat(pSPARC); + pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; + + //Reassign LatVec it old values + for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = oldLatVec[i];} + + // Update/Calculate new angles between lattice vectors + pSPARC->angle_12 = acos( pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y) ) * 180 / M_PI; + pSPARC->angle_13 = acos( pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z) ) * 180 / M_PI; + pSPARC->angle_23 = acos( pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z) ) * 180 / M_PI; + + //Update LATVEC_SCALE and LatVec + if (pSPARC->Flag_latvec_scale == 1){ + // LatVec just accounts for change in orientation/angles + for (int i = 0; i < 3; i++){ + pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; + pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; + pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; + } + + // LATVEC_SCALE accounts for change in lengths + pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; + pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; + pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; + + } + + } + //Update reciprocal lattice vectors, reciprocal metric tensor + for (int i = 0; i < 9; i++){ + old_cell[i] = pSPARC->full_lattice[i]; + } + + // Calculate the inverse of lattice-vector + double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; + double S_inv[9] = {0}; + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor + // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); + // Now computing reciprocal metric tensor, + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); + + if (update_cell == false){ + //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell@Rotation_matrix.T = old_cell; + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); + + //Initiating cell lattice vectors velocity as zero + for (int i = 0; i < 9; i++){ + pSPARC->lattice_avg_velo[i] = 0.0; + } + } + + //If updating the cell, then also calculate the velocity of cell lattice vectors (only useful in 1st MD step (if starting with nonzero lattice vector velocities: but as of now this step is not really useful, as we are by default only supporting zero initializing for lattice vector velocities)) + else { + double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; + + for (int i = 0; i < 9; i++){ + temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; + } + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + else { + cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); + + for (int i = 0; i < 9; i++){ + temp_mat_2[i] = 0.0; + } + + temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); + temp_mat_2[1] = 0.0; + temp_mat_2[2] = 0.0; + + temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; + temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; + temp_mat_2[5] = 0.0; + + temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; + temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; + temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); + } +} + + +void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + double vector[3]={0.0}; + pSPARC->KE = 0.0; + + int count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { + cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, &pSPARC->Pm_ion[count*3], 1, 0.0, vector, 1); + pSPARC->KE += cblas_ddot(3, vector, 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; + count++; + } + } + + pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); +} + + +void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 + } + + int count = 0; + for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3]; + pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+1]; + pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+2]; + pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+2] * pSPARC->ion_vel_fractional[count*3+2]; + count++; + } + } + + pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; + pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; + pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; + + cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); +} + + +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + //Initialize some useful constants + double baro_const1; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else { + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; + double baro_const3 = 1.0 / baro_const1; + double ktemp = pSPARC->kB * pSPARC->thermos_T; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; + + // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// + + // Calculating kinetic energy of ions + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); + cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel_fractional, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->metric_tensor, 3, 0.0, pSPARC->Pm_ion, 3); + int count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + cblas_dscal(3 * pSPARC->nAtomv[ityp], pSPARC->Mass[ityp], &pSPARC->Pm_ion[count], 1); + count = count + 3 * pSPARC->nAtomv[ityp]; + } + // Calculate kinetic energy and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper + pSPARC->KE_save = pSPARC->KE; + + // Calculating thermostat energies + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + + // Calculating barostat energies + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + transpose_and_add(pSPARC->Pm_metric_tensor); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3 * baro_const2, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper + + + double sumAllHamilTerms; + sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 + } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + + #ifdef DEBUG + if (rank == 0) { + printf("within init"); + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } + } + #endif + // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// + + //Initialize constraint stress to 0 + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; + } +} + +/* + @ brief: Does several things: + -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) + -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) + -update momentum + +*/ +void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double ktemp = pSPARC->kB * pSPARC->thermos_T; + int count; + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; + double internal_stress_cartesian[9]; + + //Initialize some useful constants + double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]={0}; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; + NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; + NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; + + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + else{ + NPT_NPH_ANGLES = pSPARC->NPH_ANGLES; + NPT_NPHconstraintFlag = pSPARC->NPHconstraintFlag; + NPT_NPHscaleVecs[0] = pSPARC->NPHscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPHscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPHscaleVecs[2]; + + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper + } + double baro_const3 = 1.0 / baro_const1; + + if (pSPARC->MDCount == 1){ + //Initialize constraint stress to 0 + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = 0.0; + } + } + + //#ifdef DEBUG + // printf("QMASS: %lf\n",pSPARC->NPT_NP_qmass); + // printf("SNOSE[0] %lf \n",pSPARC->SNOSE[0]); + // printf("SNOSE[1] %lf \n",pSPARC->SNOSE[1]); + // printf("SNOSE[2] %lf \n",pSPARC->SNOSE[2]); + // printf("KE %lf \n",pSPARC->KE); + // printf("Kbaro %lf \n",pSPARC->Kbaro); + // printf("Ubaro %lf \n",pSPARC->Ubaro); + // printf("InitHamil %lf \n",pSPARC->init_Hamil_NPT_NP); + + // if (rank == 0){ + // printf(":Pm_ion:\n"); + // for(int atm = 0; atm < pSPARC->n_atom; atm++){ + // printf("%18.10E %18.10E %18.10E\n", pSPARC->Pm_ion[3 * atm], pSPARC->Pm_ion[3 * atm + 1], pSPARC->Pm_ion[3 * atm + 2]); + // } + // } + // printf("Intial angles %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); + // exit(EXIT_FAILURE); + //#endif + + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + double factor; + // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof * ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; + pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; + #ifdef DEBUG + if (rank == 0) { + printf("factor Eqn.18G is %12.9f\n", factor); + printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); + } + #endif + // Update the kinetic energy of the thermostat + + pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic + pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper + + } + + // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds Eqn. 18h in the Hernandez paper + internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; + internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; + internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat_b, 3); + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, pSPARC->reciprocal_lattice, 3, temp_mat_b, 3, 0.0, pSPARC->internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); + + for (int i = 0; i < 9; i++){ + temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Eqn. 18h Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = (pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (pSPARC->NPT_NP_ANGLES == 0){ + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); + } + + } + else { + if (pSPARC->NPH_ANGLES == 0){ + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); + } + } + + //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress + for (int i = 0; i < 9; i++){ + temp_mat[i] = pSPARC->internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + //Now impose the constraints on it + if (NPT_NPHscaleVecs[2] == 0){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); + //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) + temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; + temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; + temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; + + //Update the kinetic energy of the barostat + pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + + // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) + // This setup corresponds to Eqn. 18i in Hernandez paper + double *ion_forces_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (ion_forces_fractional == NULL) { + fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); + exit(EXIT_FAILURE); + } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->forces, 3, pSPARC->full_lattice, 3, 0.0, ion_forces_fractional, 3); + // Eqn. 18i: momentum += 0.5 * dt * S * D2C + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); + count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); + count += 3 * pSPARC->nAtomv[ityp]; + } + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + + for (int i = 0; i < 9; i++){ + pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - pSPARC->internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + } + cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); + pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); + + //Update Hamiltonian + double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; + // } + pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper + } + else { + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { + // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; + // } + pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper + } + #ifdef DEBUG + if (rank == 0) { + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } + } + #endif + + // For printing, convert the total internal stress, constraint stress and the kinetic stress to cartesian coordinates + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); //Already divided by volume earlier + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->total_internal_stress, 3); //Mutliplied by 2 so as to remove the effect of previous divisions by 2 in the kinetic_stress, internal_stress_fractional + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->constraint_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->constraint_stress, 3); + + + // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// + + + // ------------------------------------- BEGIN: PRINTING FOR NPT_NP OR NPH ENSEMBLE (this marks the end of one timestep) --------------------------------------// + + // Obtain updated velocities in cartesian coordinates for use in MD_QOI function + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + + #ifdef DEBUG + if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount); + #endif + int Count = pSPARC->MDCount + pSPARC->restartCount; + int check1 = (pSPARC->PrintMDout == 1 && !rank); + + FILE *output_md; + FILE *output_fp; + + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation + if(check1) { + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n"); + fprintf(output_md,":MDSTEP: %d\n", Count); + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - pSPARC->t_md); + Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file + fclose(output_md); + } + + #ifdef DEBUG + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - pSPARC->t_md)); + #endif + if(!rank){ + output_fp = fopen(pSPARC->OutFilename,"a"); + if (output_fp == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); + exit(EXIT_FAILURE); + } + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - pSPARC->t_md)); + fclose(output_fp); + } + + // (this marks the start of MDCount^{th} step ), but do not move pSPARC->MDCount increment here, it is affecting other functions + pSPARC->t_md = MPI_Wtime(); + #ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount); + #endif + + // ------------------------------------- END: PRINTING FOR NPT_NP OR NPH ENSEMBLE (this marks the beginning of new timestep) --------------------------------------// + + + // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + // Now we update/Step-up the momenta of the Ionic particles by dt/2 + // This setup corresponds to Eqn. 18a in Hernandez paper + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); + free(ion_forces_fractional); + //Update the kinetic energy of the Ionic particles + Calculate_Ionic_particles_Kinetic_energy(pSPARC); + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); + count = 0; + for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); + count = count + 3 * pSPARC->nAtomv[ityp]; + } + // Calculate internal pressure and kinetic stress + Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + + + // Now we update/Step-up the momenta of the barostat by dt/2 + // This setup corresponds to Eqn. 18b in the Hernandez paper + // This needs to be solved iteratively + Update_metric_tensor_momenta_iteratively_half_step(pSPARC); + + //Now impose the constraints on it + if (NPT_NPHscaleVecs[2] == 0){ + pSPARC->Pm_metric_tensor[8] = 0; + pSPARC->Pm_metric_tensor[7] = 0; + pSPARC->Pm_metric_tensor[6] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + } + if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + + + + // Now we update/Step-up the momenta of the thermostat by dt/2 + // This setup corresponds to Eqn. 18c in the Hernandez paper + // Skip this step if doing NPH ensemble + if (pSPARC->NPT_NP_qmass > 0){ + double factor; + factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; + + #ifdef DEBUG + if (rank == 0) + printf("factor is %12.9f\n", factor); + #endif + if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ + if (rank == 0) + printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); + } + + pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); + #ifdef DEBUG + if (rank == 0) + printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); + #endif + } + + + // Now we update/Step-up the Position of the thermostat by dt/2 + // This setup corresponds to Eqn. 18d in the Hernandez paper + double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; + int TimeIter = 0; + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + while (1) { + S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; + if (fabs(S_temp - S_new) < 1e-7) { + break; + } + S_temp = S_new; + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + if (rank == 0){ + printf("%15.7f \n", S_new); + printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); + exit(1); + } + } + } + #ifdef DEBUG + if (rank == 0) + printf("S_temp is %12.9f\n", S_temp); + #endif + } + else{ // This gets executes when running NPH ensemble + pSPARC->SNOSE[0] = 1.0; + pSPARC->SNOSE[1] = 0.0; + } + + // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) + // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// + + + // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// + + pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; + + //Eqn. 18e is implicitly solved in the below subroutine + Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new, NPT_NPH_ANGLES, NPT_NPHconstraintFlag); + + //Before updating cell parameters, convert cartesian atomic position coordinates to fractional + double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, pSPARC->reciprocal_lattice, 3, 0.0, atom_pos_fractional, 3); + //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor + fetch_MD_cell_ingredients(pSPARC, true); + //Update Atomic position in fractional coordinates (Eqn. 18f in Hernandez paper) + cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel_fractional, 1, atom_pos_fractional, 1); + // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, atom_pos_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->atom_pos, 3); + free(atom_pos_fractional); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); + //Update atomic positions and restore ionic velocities + cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); + //cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel_fractional, 1); + + + //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume + pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential + + //Update kinetic energy and kinetic stress based on new S + pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); + + for (int i = 0; i < 9; i++){ + pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); + } + + // Update SNOSE[0] to S_new + if (pSPARC->NPT_NP_qmass > 0){ + pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; + pSPARC->SNOSE[0] = S_new; + } + // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// + // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// +} + + +void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + double a_norm; double b_norm; double c_norm; + double da_dt_norm; double db_dt_norm; double dc_dt_norm; + double baro_const4; double thermo_const1; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double constraint_velocity[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); + b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); + c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + else{ + baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper + } + + + da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); + db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); + dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); + + // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED + if (NPT_NPHconstraintFlag == 4){ + gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; + gpig[4] = gpig[0]; + gpig[8] = gpig[0]; + } + + // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED + else if (NPT_NPHconstraintFlag == 1){ + gpig[0] = (gpig[0] + gpig[4]) / 2; + gpig[4] = gpig[0]; + } + + // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED + else if (NPT_NPHscaleVecs[2] == 0 ){ + gpig[8] = 0; + gpig[7] = 0; + gpig[6] = 0; + gpig[5] = 0; + gpig[2] = 0; + } + + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + + + constraint_velocity[0] = gpig[0] * baro_const4; + constraint_velocity[4] = gpig[4] * baro_const4; + constraint_velocity[8] = gpig[8] * baro_const4; + + constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; + constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; + constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; + + constraint_velocity[3] = constraint_velocity[1]; + constraint_velocity[6] = constraint_velocity[2]; + constraint_velocity[7] = constraint_velocity[5]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); + + thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); + + // Calculating constraint stress + for (int i = 0; i < 9; i++){ + pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); + pSPARC->Pm_metric_tensor[i] = gpig[i]; + } +} + + +void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_ANGLES, int NPT_NPHconstraintFlag){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-7; // tolerance criterion for checking convergence + double baro_const11; + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); + } + else{ + baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); + } + + double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); + double baro_const7; + double det_temp_metric_tensor; + double a_norm; double b_norm; double c_norm; + + //Initialize empty temporary matrices and vectors + double gpi[9]; double gpig[9]; double gpig_old[9]; + double temp_metric_tensor[9]; double new_metric_tensor[9]; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = pSPARC->metric_tensor[i]; + gpig_old[i] = gpig[i]; + } + + while (1){ + + det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) + + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) + + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; + + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); + + baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; + + for (int i = 0; i < 9; i++){ + new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; + } + + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + if (converged){ + break; + } else{ + cblas_dscal(9, 0.5 , new_metric_tensor, 1); + transpose_and_add(new_metric_tensor); + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++){ + if (rank == 0){ + printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], + new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + } + } + + if (NPT_NPH_ANGLES == 0){ + if (NPT_NPHconstraintFlag == 4){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; + new_metric_tensor[4] = new_metric_tensor[0]; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (NPT_NPHconstraintFlag == 1){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; + new_metric_tensor[4] = new_metric_tensor[0]; + } + + a_norm = sqrt( new_metric_tensor[0] ); + b_norm = sqrt( new_metric_tensor[4] ); + c_norm = sqrt( new_metric_tensor[8] ); + + new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; + new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; + new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; + + new_metric_tensor[3] = new_metric_tensor[1]; + new_metric_tensor[6] = new_metric_tensor[2]; + new_metric_tensor[7] = new_metric_tensor[5]; + + for (int i = 0; i < 9; i++){ + temp_metric_tensor[i] = new_metric_tensor[i]; + } + } + + for (int i = 0; i < 9; i++){ + pSPARC->metric_tensor[i] = temp_metric_tensor[i]; + } + + #ifdef DEBUG + if (rank == 0) { + for (int i = 0; i < 9; i++){ + printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); + } + } + #endif + +} + + +void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //Initialize some useful constants + bool converged; // determine whether the iteration converges or not + int TimeIter = 0; // current iteration count + const double tolerance = 1e-12; // tolerance criterion for checking convergence + double baro_const0, baro_const3; + + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + + } + else{ + baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); + baro_const3 = 0.5 / baro_const0; + + } + + //Initialize empty temporary matrices and vectors + double temp_mat[9]; + double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; + double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; + + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; + } + + // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) + while (1){ + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); + + //Transpose + temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; + temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; + temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; + + pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); + + // Eqn. 18b Hernandez paper + for (int i = 0; i < 9; i++){ + temp_mat[i] = pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; + temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; + new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; + } + + cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); + transpose_and_add(new_Pm_metric_tensor); + + //Check convergence + converged = true; + for (int i = 0; i < 9; i++){ + if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ + converged = false; + break; + } + } + + // if yes then break; else resolve + if (converged){ + break; + } else{ + for (int i = 0; i < 9; i++){ + temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; + } + } + + TimeIter++; + //it iteration count exceeds max iteration counts, exit + if (TimeIter > pSPARC->maxTimeIter){ + for(int row = 0; row < 3; row++){ + if (rank == 0){ + printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], + new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); + printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); + exit(1); + } + } + } + + } + + // As converged, update the metric tensor momenta + for (int i = 0; i < 9; i++){ + pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; + #ifdef DEBUG + if (rank == 0) + printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); + #endif + } +} + + +/** + * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c + */ +void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { + carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; + carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; + carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; +} + +/** + * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c + */ +void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { + nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; + nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; + nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; +} + +/* +* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general +*/ +void Check_atomlocation(SPARC_OBJ *pSPARC) { + int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; + double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); + for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { + rc[ityp] = 0.0; + for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) + rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); + } + // Check whether the two atoms are closer than rc + for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm < count){ + rc1 = rc[ityp]; + break; + }else + continue; + } + for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ + count = 0; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + count += pSPARC->nAtomv[ityp]; + if(atm2 < count){ + rc2 = rc[ityp]; + break; + }else + continue; + } + temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); + if(temp < (1 - tol) * (rc1 + rc2)){ + if(!rank) + printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); + atm2 = pSPARC->n_atom; + atm = pSPARC->n_atom - 1; + } + } + } + free(rc); + + wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); +} + +/* +* @ brief: function to wraparound atom positions for PBC +*/ +void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { + + int rank, atm, dir = 0, maxdir = 3, BC; + double length, coord_temp;// Change tol according to the situation + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + + // Convert Cart to nonCart coordinates for non orthogonal cell + if(pSPARC->cell_typ != 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++) + Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); + } + + while(dir < maxdir){ + if(dir == 0){ + length = pSPARC->range_x; + BC = pSPARC->BCx; + } + else if(dir == 1){ + length = pSPARC->range_y; + BC = pSPARC->BCy; + } + else if(dir == 2){ + length = pSPARC->range_z; + BC = pSPARC->BCz; + } + if(BC == 1){ + if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it + for(atm = 0; atm < pSPARC->n_atom; atm++){ + if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ + if(!rank) + printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); + exit(EXIT_FAILURE); + } + } + } + } else if(BC == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + coord_temp = *(coord+3*atm+dir); + if (coord_temp < 0.0 || coord_temp >= length) + { + coord_temp = fmod(coord_temp,length); + double new_coord = coord_temp + (coord_temp<0.0)*length; + double shift = new_coord - *(coord+3*atm+dir); + *(coord+3*atm+dir) = new_coord; + if (pSPARC->CyclixFlag && opt == 1){ + wraparound_velocity(pSPARC, shift, dir, 3*atm); + } + } + } + } + dir ++; + } +} + +/* +* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC +*/ +void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { + + if (dir == 1){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; + pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; + } + } else if (dir == 2){ + if (pSPARC->MDFlag == 1){ + double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; + pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + else if (pSPARC->RelaxFlag == 1){ + double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; + pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; + pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; + } + } + +} + + + +/* + @ brief: function to write all relevant DFT quantities generated during MD simulation +*/ +void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { + int atm; + + // Print Description of all variables + if(pSPARC->MDCount == -1){ + fprintf(output_md,":Description: \n\n"); + fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); + fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" + " where atu is the atomic unit of time, hbar/Ha \n"); + fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); + fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); + fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); + fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" + " where N = number of particles, k = Boltzmann constant\n"); + fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); + fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + if (pSPARC->Flag_latvec_scale == 0) + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + else + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha \n"); + } + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); + fprintf(output_md,":Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 \n"); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = 1 \n",pSPARC->MDMeth); + } else { + fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); + } + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); + fprintf(output_md,":Desc_SNOSE[0]: Position variable of the thermostat\n"); + fprintf(output_md,":Desc_SNOSE[1]: Velocity variable of the thermostat\n"); + } else + fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha \n"); + } + if(pSPARC->Calc_stress == 1){ + fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) + fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); + fprintf(output_md,":Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated as: kinetic_stress (positive convention) - electronic stress - constraint stress; as per (E. Hernandez, 2001) paper + } + } + if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ + fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); + fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ + fprintf(output_md,":Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa \n"); + fprintf(output_md,":Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa \n"); + } + fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" + " where N = number of particles, k = Boltzmann constant, V = volume\n"); + } + + #ifdef DEBUG + fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); + #endif + + fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); + fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); + fprintf(output_md, "\n\n"); + } else{ + double ken_ig = 0.0; + ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; + + // Print Temperature and energy + fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); + fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); + fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); + fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); + fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); + fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); + fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); + fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); + fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); + } + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH); + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); + fprintf(output_md,":SNOSE[0]:%18.10E \n", pSPARC->SNOSE[0]); + fprintf(output_md,":SNOSE[1]:%18.10E \n", pSPARC->SNOSE[1]); + } if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); + + // Print atomic position + if(pSPARC->PrintAtomPosFlag){ + fprintf(output_md,":R:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + } + + // Print velocity + if(pSPARC->PrintAtomVelFlag){ + fprintf(output_md,":V:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + } + + // Print Forces + if(pSPARC->PrintForceFlag){ + fprintf(output_md,":F:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); + } + } + + // Print length of lattice vectors + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(output_md,":ANGLES:\n"); + fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); + fprintf(output_md,":VOLUME: %18.10E\n", pSPARC->volumeCell); + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(output_md,":CELL:\n"); + fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); + fprintf(output_md,":LatUVec: \n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] + , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] + , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); + } else { + fprintf(output_md,":LATVEC_SCALE:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x / pSPARC->initialLatVecLength[0], pSPARC->range_y / pSPARC->initialLatVecLength[1], pSPARC->range_z / pSPARC->initialLatVecLength[2]); + fprintf(output_md,":LatVec:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] + , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] + , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); + } + } + + // Print stress + if(pSPARC->Calc_stress == 1){ + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + fprintf(output_md,":STRIO:\n"); + PrintStress (pSPARC, pSPARC->stress_i, output_md); + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; + PrintStress (pSPARC, stress_e, output_md); + } + + else{ //Trigger NPT_NP or NPH ensemble stress printing + fprintf(output_md,":STRIO:\n"); //Ion-kinetic stress + double temp_stress[6]; + temp_stress[0] = pSPARC->kinetic_stress[0]; temp_stress[1] = pSPARC->kinetic_stress[1]; temp_stress[2] = pSPARC->kinetic_stress[2]; + temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[8]; + PrintStress (pSPARC, temp_stress, output_md); //Print kinetic stress as defined in the (E. Hernandez, 2001) paper + fprintf(output_md,":STRESS:\n"); + double stress_e[6]; // electronic stress + for (int i = 0; i < 6; i++) + stress_e[i] = pSPARC->stress[i]; // stress_i or ionic stress function is never called in NPT_NP or NPH ensemble, so pSPARC->stress does not include contribution from it, and thus no need to subtract stress_i from pSPARC->stress, as done in other ensembles + PrintStress (pSPARC, stress_e, output_md); + fprintf(output_md,":CONSTRESS:\n"); //Constraint stress + temp_stress[0] = pSPARC->constraint_stress[0]; temp_stress[1] = pSPARC->constraint_stress[1]; temp_stress[2] = pSPARC->constraint_stress[2]; + temp_stress[3] = pSPARC->constraint_stress[4]; temp_stress[4] = pSPARC->constraint_stress[5]; temp_stress[5] = pSPARC->constraint_stress[8]; + PrintStress (pSPARC, temp_stress, output_md); + fprintf(output_md,":TOTSTRESS:\n"); //Print total internal stress accouting for the constraints in NPT_NP or NPH ensemble + temp_stress[0] = pSPARC->total_internal_stress[0]; temp_stress[1] = pSPARC->total_internal_stress[1]; temp_stress[2] = pSPARC->total_internal_stress[2]; + temp_stress[3] = pSPARC->total_internal_stress[4]; temp_stress[4] = pSPARC->total_internal_stress[5]; temp_stress[5] = pSPARC->total_internal_stress[8]; + PrintStress (pSPARC, temp_stress, output_md); + } + } + // print pressure + if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { + // find pressure of ideal gas: NkT/V + // Define measure of unit cell + double cell_measure = pSPARC->Jacbdet; + if(pSPARC->BCx == 0) + cell_measure *= pSPARC->range_x; + if(pSPARC->BCy == 0) + cell_measure *= pSPARC->range_y; + if(pSPARC->BCz == 0) + cell_measure *= pSPARC->range_z; + double pres_ig = 0.0; + pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i) * CONST_HA_BOHR3_GPA); + } + else{ //Trigger NPT_NP or NPH ensemble stress printing + double ion_kinetic_pressure, constraint_pressure; + ion_kinetic_pressure = 1.0 / 3.0 * (pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[4] + pSPARC->kinetic_stress[8]); //Kinetic stress is already multiplied by 2 + constraint_pressure = 1.0 / 3.0 * (pSPARC->constraint_stress[0] + pSPARC->constraint_stress[4] + pSPARC->constraint_stress[8]); //Constraint stress is already multiplied by 2 + fprintf(output_md,":PRESIO: %18.10E\n", ion_kinetic_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PRES: %18.10E\n", (pSPARC->internal_pressure - ion_kinetic_pressure + constraint_pressure) * CONST_HA_BOHR3_GPA); + fprintf(output_md,":CONPRES: %18.10E\n", constraint_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":TOTPRES: %18.10E\n", pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); //Also accounts for pressure due to constraint stress + } + + fprintf(output_md,":PRESIG: %18.10E\n", pres_ig * CONST_HA_BOHR3_GPA); // Ideal Gas + + } + + #ifdef DEBUG + // Print Statistical properties + fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(output_md,":PREST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":MEAN_TOTSTRESS:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->mean_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[2] * CONST_HA_BOHR3_GPA + , pSPARC->mean_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[5] * CONST_HA_BOHR3_GPA + , pSPARC->mean_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[8] * CONST_HA_BOHR3_GPA); + fprintf(output_md,":STD_TOTSTRESS:\n"); + fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->std_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[2] * CONST_HA_BOHR3_GPA + , pSPARC->std_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[5] * CONST_HA_BOHR3_GPA + , pSPARC->std_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[8] * CONST_HA_BOHR3_GPA); + fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fprintf(output_md,":AVGV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",avgvel[atm]); + fprintf(output_md,":MAXV:\n"); + for(atm = 0; atm < pSPARC->Ntypes; atm++) + fprintf(output_md," %18.10E\n",maxvel[atm]); + #endif + fprintf(output_md,":MIND:\n"); + char elemType1[8], elemType2[8]; + int typeIndex, typeIndex2, pairIndex; + for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); + } + pairIndex = 0; + for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { + find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); + for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { + find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); + fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); + pairIndex++; + } + } + } +} + +/* + @ brief function to evaluate the quantities of interest in a MD simulation +*/ +void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { + // Compute MD energies (TE=KE+PE)/atom and temperature + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); + if(pSPARC->ion_elec_eqT == 1){ + pSPARC->elec_T = pSPARC->ion_T; + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + } + pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; + pSPARC->KE = pSPARC->KE / pSPARC->n_atom; + pSPARC->TE = (pSPARC->PE + pSPARC->KE); + // Extended System (Ionic system + Thermostat) energy + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; + } + + // Compute Ionic stress/pressure + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) + Calculate_ionic_stress(pSPARC); + } + + // Calculate_stress(pSPARC); +#ifdef DEBUG + // MD Statistics + double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old, mean_total_internal_stress_old[9]; + int Count; + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; + } + else{ + Count = pSPARC->MDCount + pSPARC->restartCount; + } + mean_Te_old = pSPARC->mean_elec_T; + mean_Ti_old = pSPARC->mean_ion_T; + mean_TE_old = pSPARC->mean_TE; + mean_KE_old = pSPARC->mean_KE; + mean_PE_old = pSPARC->mean_PE; + mean_U_old = pSPARC->mean_U; + mean_Eent_old = pSPARC->mean_Entropy; + mean_internal_pressure_old = pSPARC->mean_internal_pressure; + for (int i = 0; i < 9; i++){mean_total_internal_stress_old[i] = pSPARC->mean_total_internal_stress[i];} + pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; + pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; + pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; + for (int i = 0; i < 9; i++){pSPARC->mean_total_internal_stress[i] = (mean_total_internal_stress_old[i] * (Count - 1) + pSPARC->total_internal_stress[i]) / Count;} + pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; + pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; + pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; + pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; + pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); + pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); + pSPARC->std_internal_pressure = sqrt(fabs( ((pow(pSPARC->std_internal_pressure,2.0) + pow(mean_internal_pressure_old,2.0)) * (Count - 1) + pow(pSPARC->internal_pressure,2.0))/Count - pow(pSPARC->mean_internal_pressure,2.0) )); + for (int i = 0; i < 9; i++){pSPARC->std_total_internal_stress[i] = sqrt(fabs( ((pow(pSPARC->std_total_internal_stress[i],2.0) + pow(mean_total_internal_stress_old[i],2.0)) * (Count - 1) + pow(pSPARC->total_internal_stress[i],2.0))/Count - pow(pSPARC->mean_total_internal_stress[i],2.0) ));} + pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); + pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); + pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); + pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); + pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + double mean_TEx_old = pSPARC->mean_TE_ext; + pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; + pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); + } +#endif + + // Average and maximum speed + int ityp, atm, cc = 0; + double temp; + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + maxvel[ityp] = 0.0; + avgvel[ityp] = 0.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); + if(temp > maxvel[ityp]) + maxvel[ityp] = temp; + avgvel[ityp] += temp; + cc += 1; + } + avgvel[ityp] /= pSPARC->nAtomv[ityp]; + } + + // Average and minimum distance + //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); + int atm2, ityp2, cc2, pairIndex; + cc = 0; + + // Store the cell as a 3x3 lattice vector + double *lattice = (double *)calloc(9, sizeof(double)); + double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; + double dr[3]; + int row, col; + for (row = 0; row < 3; row++) { + lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; + lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; + lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; + } + + // Calculate the inverse of lattice-vector + double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; + double S_inv[9] = {0}; + int m = 3; + + for (int JJ = 0; JJ < 9; JJ++) { + LatVec[JJ] = lattice[JJ]; + } + + /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ + // Compute SVD of LatVec(LV) first: LV = U * S * V^T + LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); + + // First compute S^{-1} + for (int i = 0; i < 3; i++) { + if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; + } + + // Compute LV^{-1} = V * S^{-1} * U^T + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); + + for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ + mindis[ityp] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ + for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[ityp]) + mindis[ityp] = temp; + } + } + cc += pSPARC->nAtomv[ityp]; + } + cc = 0; + pairIndex = pSPARC->Ntypes; + for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ + cc2 = pSPARC->nAtomv[ityp] + cc; + for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ + // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; + mindis[pairIndex] = 1000000000.0; + for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ + for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ + // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); + + // Vector connecting atoms atm and atm2 + dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; + dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; + dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; + + double frac[3], dr_pbc[3]; + + // Minimum Image Convention (MIC) in fractional coordinates + // frac = LV^{-1} * dr + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); + + // Wrap into [-0.5, 0.5) + frac[0] -= round(frac[0]); + frac[1] -= round(frac[1]); + frac[2] -= round(frac[2]); + + // dr_pbc = lattice * frac + cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); + + // Calculate distance + temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); + + if(temp < mindis[pairIndex]) + mindis[pairIndex] = temp; + } + } + pairIndex++; + cc2 += pSPARC->nAtomv[ityp2]; + } + cc += pSPARC->nAtomv[ityp]; + } + free(lattice); +} + +/* + @ brief: function to write all relevant quantities needed for MD restart +*/ +void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { + FILE *mdout; + if(!Flag){ + mdout = fopen(pSPARC->restartC_Filename,"r+"); + if(mdout == NULL){ + printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); + exit(EXIT_FAILURE); + } + // Update MD Count + + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + fclose(mdout); + + } + else{ + if (print_restart_typ == 0) { + // Transfer the restart content to a file before overwriting + Rename_restart(pSPARC); + // Overwrite in the restart file + mdout = fopen(pSPARC->restartC_Filename,"w"); + } + else + mdout = fopen(pSPARC->restart_Filename,"w"); + + // Print restart Count + printf("\n"); + printf("\n"); + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + // Print atomic position + int atm; + fprintf(mdout,":R(Bohr):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); + } + + // Print velocity + fprintf(mdout,":V(Bohr/atu):\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); + } + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + fprintf(mdout,":Pm_ion:\n"); + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->Pm_ion[3 * atm], pSPARC->Pm_ion[3 * atm + 1], pSPARC->Pm_ion[3 * atm + 2]); + } + } + // Print extended system parameters in case of NVT + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":snose: %.15g\n", pSPARC->snose); + fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); + } + // Print extended system parameters in case of NPT-NH + if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + int thenos; + fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); + fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); + } + fprintf(mdout,"\n"); + fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter + fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters + for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { + if (thenos%5 == 0){ + fprintf(mdout,"\n"); + } + fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); + } + fprintf(mdout,"\n"); + if (pSPARC->Flag_latvec_scale == 0) + fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) + else + fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); + } + // Print extended system parameters in case of NPT-NP or NPH ensemble + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); + fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); + fprintf(mdout,":NPT_NP_SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep + fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter + fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep + fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPH_bmass); + fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); + } + fprintf(mdout,":KE: %.15g\n",pSPARC->KE); + fprintf(mdout,":Kbaro: %.15g\n",pSPARC->Kbaro); + fprintf(mdout,":Ubaro: %.15g\n",pSPARC->Ubaro); + fprintf(mdout,":kinetic_stress: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->kinetic_stress[0], pSPARC->kinetic_stress[1], pSPARC->kinetic_stress[2] + , pSPARC->kinetic_stress[3], pSPARC->kinetic_stress[4], pSPARC->kinetic_stress[5] + , pSPARC->kinetic_stress[6], pSPARC->kinetic_stress[7], pSPARC->kinetic_stress[8]); + fprintf(mdout,":Pm_metric_tensor: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] + , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] + , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // velocity of lattice + if (pSPARC->Flag_latvec_scale == 0){ + fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); + fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] + , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] + , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); + } else { + fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); + fprintf(mdout,":LatVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] + , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] + , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); + } + fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI ); + fprintf(mdout,":ROTATION_MATRIX: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] + , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] + , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); + fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); + fprintf(mdout,":EXTERNAL_PRESSURE: %.15g\n", pSPARC->pressure_external * CONST_HA_BOHR3_GPA); + fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[1] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[2] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[3] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[4] * CONST_HA_BOHR3_GPA + ,pSPARC->stress_external[5] * CONST_HA_BOHR3_GPA); + } + // Print temperature + fprintf(mdout,":TEL(K): %18.10E\n", pSPARC->elec_T); + fprintf(mdout,":TIO(K): %18.10E\n", pSPARC->ion_T); + fprintf(mdout,":TELST(K): %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); + fprintf(mdout,":TIOST(K): %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); + fprintf(mdout,":PREST(Gpa): %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(mdout,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); + fprintf(mdout,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); + fprintf(mdout,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); + fprintf(mdout,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); + fprintf(mdout,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + fprintf(mdout,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); + } + fclose(mdout); + } +} + +/* +@ brief function to read the restart file for MD restart +*/ +void RestartMD(SPARC_OBJ *pSPARC) { + int rank, position, l_buff = 0; +#ifdef DEBUG + double t1, t2; +#endif + char *buff; + FILE *rst_fp = NULL; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // Open the restart file + if(!rank){ + //char rst_Filename[L_STRING]; + if( access(pSPARC->restart_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restart_Filename,"r"); + else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rst_fp = fopen(pSPARC->restartC_Filename,"r"); + else + rst_fp = fopen(pSPARC->restartP_Filename,"r"); + } +#ifdef DEBUG + if(!rank) + printf("Reading .restart file for MD\n"); +#endif + // Allocate memory for dynamic variables + pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->ion_vel == NULL) { + printf("\nCannot allocate memory for ion velocity array!\n"); + exit(EXIT_FAILURE); + } + + + if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ + pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); + if (pSPARC->Pm_ion == NULL) { + printf("\nCannot allocate memory for ion momentum array!\n"); + exit(EXIT_FAILURE); + } + } + + // Allocate memory for Pack and Unpack to be used later for broadcasting + if(pSPARC->RestartFlag == 1){ + // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 20)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 56 + 32)) * sizeof(double); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 52 + 32)) * sizeof(double); + } + else { + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 22) * sizeof(double); + } + } + else if(pSPARC->RestartFlag == -1) + l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); + + buff = (char *)malloc( l_buff*sizeof(char) ); + if (buff == NULL) { + printf("\nmemory cannot be allocated for buffer\n"); + exit(EXIT_FAILURE); + } + if(!rank){ + char str[L_STRING]; + int atm; + while (fscanf(rst_fp,"%s",str) != EOF){ + if (strcmpi(str, ":STOPCOUNT:") == 0) + fscanf(rst_fp,"%d",&pSPARC->StopCount); + else if (strcmpi(str,":MDSTEP:") == 0) + fscanf(rst_fp,"%d",&pSPARC->restartCount); + else if (strcmpi(str,":R(Bohr):") == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); + } + } else if (strcmpi(str,":V(Bohr/atu):") == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); + } + } else if (strcmpi(str,":Pm_ion:") == 0){ + for(atm = 0; atm < pSPARC->n_atom; atm++){ + fscanf(rst_fp,"%lf %lf %lf", &pSPARC->Pm_ion[3 * atm], &pSPARC->Pm_ion[3 * atm + 1], &pSPARC->Pm_ion[3 * atm + 2]); + } + } + else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->snose); + else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->xi_nose); + else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->elec_T); + else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->ion_T); + else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TELST(K):") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_elec_T); fscanf(rst_fp,"%lf", &pSPARC->std_elec_T); + }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); + }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); + pSPARC->mean_internal_pressure /= CONST_HA_BOHR3_GPA; pSPARC->std_internal_pressure /= CONST_HA_BOHR3_GPA; + }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); + }else if (strcmpi(str,":KENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_KE); fscanf(rst_fp,"%lf", &pSPARC->std_KE); + }else if (strcmpi(str,":FENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_PE); fscanf(rst_fp,"%lf", &pSPARC->std_PE); + }else if (strcmpi(str,":UENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_U); fscanf(rst_fp,"%lf", &pSPARC->std_U); + }else if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_Entropy); fscanf(rst_fp,"%lf", &pSPARC->std_Entropy); + } + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ + fscanf(rst_fp,"%lf", &pSPARC->mean_TE_ext); fscanf(rst_fp,"%lf", &pSPARC->std_TE_ext); + } + } + if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { + if (strcmpi(str,":NPT_NH_QMASS:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { + fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); + for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ + fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); + } + fscanf(rst_fp, "%*[^\n]\n"); + } + + else if (strcmpi(str,":NPT_NH_BMASS:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); + else if (strcmpi(str,":NPT_NH_vlogv:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->vlogv); + else if (strcmpi(str,":CELL:") == 0) { + double nowRange_x, nowRange_y, nowRange_z; + fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); + fscanf(rst_fp, "%*[^\n]\n"); + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + double nowLatScale_x, nowLatScale_y, nowLatScale_z; + fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); + fscanf(rst_fp, "%*[^\n]\n"); + + double nowRange_x, nowRange_y, nowRange_z; + pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); + pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); + pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); + nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; + nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; + nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; + + if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio + else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; + else pSPARC->scale = nowRange_z / pSPARC->range_z; + + pSPARC->range_x = nowRange_x; + pSPARC->range_y = nowRange_y; + pSPARC->range_z = nowRange_z; + } + else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":TARGET_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->prtarget); + } + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[0]); + else if (strcmpi(str,":NPT_NP_SNOSE[1]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[1]); + else if (strcmpi(str,":NPT_NP_SNOSE[2]:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->SNOSE[2]); + else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); + } + if (strcmpi(str,":KE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->KE); + else if (strcmpi(str,":Kbaro:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->Kbaro); + else if (strcmpi(str,":Ubaro:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->Ubaro); + else if (strcmpi(str,":kinetic_stress:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[0]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[1]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[2]); + fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[3]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[4]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[5]); + fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[6]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[7]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[8]); + } else if (strcmpi(str,":Pm_metric_tensor:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[0]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[1]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[2]); + fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[3]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[4]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[5]); + fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[6]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[7]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[8]); + } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); + for (int i = 0; i < 3; i++){pSPARC->initialLatVecAngles[i] = cos(M_PI / 180 * pSPARC->initialLatVecAngles[i]);} + } else if (strcmpi(str,":CELL:") == 0) { + fscanf(rst_fp,"%lf", &pSPARC->range_x); fscanf(rst_fp,"%lf", &pSPARC->range_y); fscanf(rst_fp,"%lf", &pSPARC->range_z); + } else if (strcmpi(str,":LatUVec:") == 0) { + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); + fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); + } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { + fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); + + fscanf(rst_fp, "%*[^\n]\n"); + } else if (strcmpi(str,":LatVec:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); + fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); + fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); + } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); + fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[6]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[7]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[8]); + } else if (strcmpi(str,":TTHRMI(K):") == 0) + fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); + else if (strcmpi(str,":EXTERNAL_PRESSURE:") == 0) + fscanf(rst_fp,"%lf", &pSPARC->pressure_external); + else if (strcmpi(str,":EXTERNAL_STRESS:") == 0){ + fscanf(rst_fp,"%lf", &pSPARC->stress_external[0]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[1]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[2]); + fscanf(rst_fp,"%lf", &pSPARC->stress_external[3]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[4]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[5]); + } + } + } + fclose(rst_fp); + + // Pack the variables + position = 0; + MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + MPI_Pack(pSPARC->Pm_ion, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->mean_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Pack(&pSPARC->mean_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->std_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + + MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Pack(pSPARC->SNOSE, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + MPI_Pack(&pSPARC->KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->Kbaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->Ubaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->kinetic_stress, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + if (pSPARC->Flag_latvec_scale == 0){ + MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + else if (pSPARC->Flag_latvec_scale == 1){ + MPI_Pack(&pSPARC->latvec_scale_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->latvec_scale_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->latvec_scale_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + MPI_Pack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); + } + } + + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); + } else{ +#ifdef DEBUG + t1 = MPI_Wtime(); +#endif + // broadcast the packed buffer + MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); +#ifdef DEBUG + t2 = MPI_Wtime(); + if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); +#endif + // unpack the variables + position = 0; + MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + if(pSPARC->RestartFlag == 1){ + if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + MPI_Unpack(buff, l_buff, &position, pSPARC->Pm_ion, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); + } + MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); + if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); + + MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + MPI_Unpack(buff, l_buff, &position, pSPARC->SNOSE, 3, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); + } + MPI_Unpack(buff, l_buff, &position, &pSPARC->KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->Kbaro, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->Ubaro, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->kinetic_stress, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, MPI_COMM_WORLD); + if (pSPARC->Flag_latvec_scale == 0){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->LatUVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); + } + else if (pSPARC->Flag_latvec_scale == 1){ + MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->LatVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); + } + MPI_Unpack(buff, l_buff, &position, pSPARC->rotation_matrix, 9, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, &pSPARC->pressure_external, 1, MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(buff, l_buff, &position, pSPARC->stress_external, 6, MPI_DOUBLE, MPI_COMM_WORLD); + } + } + + } + if(pSPARC->RestartFlag == 1) { + pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); + if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0)) { + reinitialize_mesh_NPT(pSPARC); + } + // For NPT_NP and NPH the 'reinitialize_mesh_NPT' function is being called from 'fetch_MD_cell_ingredients_restart' after calculating new Jacbdet, cell volume etc + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)||(strcmpi(pSPARC->MDMeth,"NPH") == 0) ){ + fetch_MD_cell_ingredients_restart(pSPARC); + //Now reinitialize mesh based on calculated Jacbdet and other ingredients + reinitialize_mesh_NPT(pSPARC); + } + } + free(buff); +} + + + +/* +@ brief: function to rename the restart file +*/ +void Rename_restart(SPARC_OBJ *pSPARC) { + if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) + rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); +} \ No newline at end of file diff --git a/src/include/isddft.h b/src/include/isddft.h index 38c66a13..e1ecf20a 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -920,7 +920,7 @@ typedef struct _SPARC_OBJ{ double init_Hamil_NPT_NP; // initial Hamiltonian in NPT_NP ensemble double init_Hamil_NPH; // initial Hamiltonian in NPH ensemble double KE_save; - double t_md; + double t_run_md; //NPT_NP_specific double NPT_NP_qmass; // fictitious mass of thermostat (qmass) used in NPT_NP double NPT_NP_bmass; // fictitious mass of barostat (bmass) used in NPT_NP diff --git a/src/include/md.h b/src/include/md.h index 02c5b36c..f244e53f 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -156,9 +156,9 @@ void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC); @ brief: Performs Molecular Dynamics using NPT_NP. */ -void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis); +void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis); -void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis); +void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis); /* @ brief: Calculates cell angles, reciprocal lattice vectors, metric and reciprocal metric tensors, for use in NPT_NP and NPH dynamics */ @@ -184,7 +184,7 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC); * @ brief: function to convert non cartesian to cartesian coordinates and velocities, from initialization.c */ void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord); -void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC); +//void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC); /* * @brief: function to convert cartesian to non cartesian coordinates and velocities, from initialization.c diff --git a/src/md.c b/src/md.c index eeeb12d9..4e5c5b8b 100644 --- a/src/md.c +++ b/src/md.c @@ -46,6 +46,8 @@ void main_MD(SPARC_OBJ *pSPARC) { int print_restart_typ = 0; double t_init, t_acc, *avgvel, *maxvel, *mindis; t_init = MPI_Wtime(); + pSPARC->t_run_md = MPI_Wtime(); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); @@ -86,9 +88,12 @@ void main_MD(SPARC_OBJ *pSPARC) { pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; + int check1 = (pSPARC->PrintMDout == 1 && !rank); + int check2 = (pSPARC->Printrestart == 1 && !rank); + if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // For NPT_NP and NPH, a similar but slightly modified printing scheme is run, as the printing instances in this below setup is not compatible with NPT_NP and NPH ensemble, i.e. the printing setup in the below scheme (if condition) if used for NPT_NP and NPH would be corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies. So the quantities are not in-sync when being printed to 'log' or 'aimd' file, so this setup is done separately for NPT_NP and NPH with printing happening when all quantities are in-sync and belong to same time = t - // File output_md stores all the desirable properties from a MD run FILE *output_md, *output_fp; + // File output_md stores all the desirable properties from a MD run if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ output_md = fopen(pSPARC->MDFilename,"w"); if (output_md == NULL) { @@ -124,8 +129,6 @@ void main_MD(SPARC_OBJ *pSPARC) { // Perform MD until maxStep is reached or total walltime is hit int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ t_init = MPI_Wtime(); @@ -190,7 +193,8 @@ void main_MD(SPARC_OBJ *pSPARC) { } else { // Carry out the above procedure in slightly modified printing manner for NPT_NP and NPH ensemble // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; + FILE *output_md; + if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ output_md = fopen(pSPARC->MDFilename,"w"); if (output_md == NULL) { @@ -211,36 +215,31 @@ void main_MD(SPARC_OBJ *pSPARC) { fclose(output_md); } - pSPARC->MDCount++ + pSPARC->MDCount++; pSPARC->elecgs_Count++; // Perform MD until maxStep is reached or total walltime is hit int Count = pSPARC->MDCount + pSPARC->restartCount; // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); + #ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", Count); + #endif + t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ t_init = MPI_Wtime(); - #ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); - #endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,":MDSTEP: %d\n", Count); - } - - NPT_NP_and_NPH(pSPARC, output_md, avgvel, maxvel, mindis); + + NPT_NP_and_NPH(pSPARC, avgvel, maxvel, mindis); // This is true, restart happens from the instance when position are at time = t, whereas momenta are lagging behind by dt/2, so they belong to time = t-dt/2 (unlike printing all quantities to an MD file, which happens when all quantities belong to time = t, and in-sync with each other) if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written PrintMD(pSPARC, 1, print_restart_typ); - // pSPARC->MDCount ++; // This is incremented within 'NPT_NP_and_NPH_main' subroutine - Count ++; // This should not be moved to 'NPT_NP_and_NPH_main' subroutine + if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated + pSPARC->MDCount++; + break; + } + pSPARC->MDCount ++; + Count ++; t_acc += (MPI_Wtime() - t_init)/60; } // end while loop @@ -1445,18 +1444,18 @@ The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. Additional Reference for NPH: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." Physical Review B 55.14 (1997): 8733. */ -void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { +void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - //MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); //Stress_i is never used in this ensemble - + MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); + //Calculate initial hamitonian if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)){ NPT_NP_and_NPH_init_hamiltonian(pSPARC); } //NPT_NPH_main routine - NPT_NPH_main(pSPARC, output_md, avgvel, maxvel, mindis); + NPT_NPH_main(pSPARC, avgvel, maxvel, mindis); // Reinitialize mesh size and related variables after changing size of cell reinitialize_mesh_NPT(pSPARC); // Charge extrapolation (for better rho_guess) @@ -1496,7 +1495,7 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double old_cell[9]; old_LatVec[9]; + double old_cell[9]; double oldLatVec[9]; //Compute Cell lattice vectors (scaled by LATVEC scale) if (pSPARC->Flag_latvec_scale == 0){ @@ -1531,7 +1530,7 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ } //Assign full_lattice to LatVec for updating various quantities in 'Cart2nonCart_transformMat' - for (int i = 0; i < 9; i++){old_LatVec[i] = pSPARC->LatVec[i];} + for (int i = 0; i < 9; i++){oldLatVec[i] = pSPARC->LatVec[i];} for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = pSPARC->full_lattice[i];} //Update LatUVec, Jacbdet, metricT, gradT, lapcT (this function updates all quantites based on 'LatVec' variable as input, but we actually want it based on 'full_lattice' variable, which contains all the cell lattice vectors updates, so we do the step above this to assign full_lattice to LatVec) @@ -1650,7 +1649,8 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); //Assign full_lattice to LatVec for updating various quantities in 'Cart2nonCart_transformMat' - for (int i = 0; i < 9; i++){old_LatVec[i] = pSPARC->LatVec[i];} + double oldLatVec[9]; + for (int i = 0; i < 9; i++){oldLatVec[i] = pSPARC->LatVec[i];} for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = pSPARC->full_lattice[i];} //Update LatUVec, Jacbdet, metricT, gradT, lapcT (this function updates all quantites based on 'LatVec' variable as input, but we actually want it based on 'full_lattice' variable, which contains all the cell lattice vectors updates, so we do the step above this to assign full_lattice to LatVec) @@ -1838,7 +1838,8 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ // Calculate kinetic energy and kinetic stress Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - + pSPARC->KE_save = pSPARC->KE; + // Calculating thermostat energies pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper @@ -1877,7 +1878,30 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ } pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper } + + #ifdef DEBUG + if (rank == 0) { + printf("within init"); + printf("\n"); + printf("rank %d", rank); + printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); + printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); + printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); + printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); + printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); + printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); + printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); + printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); + if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); + } + else { + printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); + } + } + #endif // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// + } /* @@ -1887,7 +1911,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ -update momentum */ -void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { +void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); double ktemp = pSPARC->kB * pSPARC->thermos_T; @@ -1921,6 +1945,8 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma pSPARC->constraint_stress[i] = 0.0; } } + + //#ifdef DEBUG // printf("QMASS: %lf\n",pSPARC->NPT_NP_qmass); // printf("SNOSE[0] %lf \n",pSPARC->SNOSE[0]); // printf("SNOSE[1] %lf \n",pSPARC->SNOSE[1]); @@ -1929,7 +1955,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // printf("Kbaro %lf \n",pSPARC->Kbaro); // printf("Ubaro %lf \n",pSPARC->Ubaro); // printf("InitHamil %lf \n",pSPARC->init_Hamil_NPT_NP); - // //; + // if (rank == 0){ // printf(":Pm_ion:\n"); // for(int atm = 0; atm < pSPARC->n_atom; atm++){ @@ -1938,6 +1964,8 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // } // printf("Intial angles %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); // exit(EXIT_FAILURE); + //#endif + // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// double factor; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) @@ -2114,22 +2142,26 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma #endif int Count = pSPARC->MDCount + pSPARC->restartCount; int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); + FILE *output_md; + FILE *output_fp; + MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - pSPARC->t_md); + output_md = fopen(pSPARC->MDFilename,"a+"); + if (output_md == NULL) { + printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); + exit(EXIT_FAILURE); + } + fprintf(output_md,"\n\n"); + fprintf(output_md,":MDSTEP: %d\n", Count); + fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - pSPARC->t_run_md); Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) fclose(output_md); + } + #ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - pSPARC->t_md)); + if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - pSPARC->t_run_md)); #endif if(!rank){ output_fp = fopen(pSPARC->OutFilename,"a"); @@ -2137,13 +2169,15 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); exit(EXIT_FAILURE); } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - pSPARC->t_md)); + fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - pSPARC->t_run_md)); fclose(output_fp); } - //Increment MDCount by 1 (this marks the start of MDCount^{th} step ) - pSPARC->MDCount++; - + // (this marks the start of MDCount^{th} step ), but do not move pSPARC->MDCount increment here, it is affecting other functions + pSPARC->t_run_md = MPI_Wtime(); + #ifdef DEBUG + if(!rank) printf(":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount); + #endif // ------------------------------------- END: PRINTING FOR NPT_NP OR NPH ENSEMBLE (this marks the beginning of new timestep) --------------------------------------// @@ -2506,7 +2540,7 @@ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ bool converged; // determine whether the iteration converges or not int TimeIter = 0; // current iteration count const double tolerance = 1e-12; // tolerance criterion for checking convergence - double baro_const0, baro_const3, baro_const5; + double baro_const0, baro_const3; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); @@ -2750,6 +2784,7 @@ void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { } + /* @ brief: function to write all relevant DFT quantities generated during MD simulation */ @@ -2781,7 +2816,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); else fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); + fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha \n"); } if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ @@ -2789,10 +2824,10 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 \n"); if (pSPARC->Flag_latvec_scale == 0){ fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = 1 \n"); + fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = 1 \n",pSPARC->MDMeth); } else { fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n"); + fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); } if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); @@ -2846,13 +2881,13 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); } if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH / pSPARC->n_atom); + fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH); if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); //This is full hamiltonian, not per atom as this is what should be measured to ensure conservation + fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); fprintf(output_md,":SNOSE[0]:%18.10E \n", pSPARC->SNOSE[0]); fprintf(output_md,":SNOSE[1]:%18.10E \n", pSPARC->SNOSE[1]); } if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); //This is full hamiltonian, not per atom as this is what should be measured to ensure conservation + fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); // Print atomic position if(pSPARC->PrintAtomPosFlag){ @@ -2879,13 +2914,6 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma } // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ fprintf(output_md,":ANGLES:\n"); fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); @@ -2976,7 +3004,7 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma // Print Statistical properties fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":PRESST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); + fprintf(output_md,":PREST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); fprintf(output_md,":MEAN_TOTSTRESS:\n"); fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->mean_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[2] * CONST_HA_BOHR3_GPA , pSPARC->mean_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[5] * CONST_HA_BOHR3_GPA @@ -3047,7 +3075,13 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { #ifdef DEBUG // MD Statistics double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old, mean_total_internal_stress_old[9]; - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; + int Count; + if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ + Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; + } + else{ + Count = pSPARC->MDCount + pSPARC->restartCount; + } mean_Te_old = pSPARC->mean_elec_T; mean_Ti_old = pSPARC->mean_ion_T; mean_TE_old = pSPARC->mean_TE; @@ -3227,8 +3261,12 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { exit(EXIT_FAILURE); } // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount); + } + else{ + fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + } fclose(mdout); } @@ -3245,7 +3283,12 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { // Print restart Count printf("\n"); printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount ); + } + else{ + fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); + } // Print atomic position int atm; fprintf(mdout,":R(Bohr):\n"); @@ -3800,7 +3843,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { if(pSPARC->RestartFlag == 1) { pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0)) { - reinitialize_mesh_NPT(pSPARC); + reinitialize_mesh_NPT(pSPARC); } // For NPT_NP and NPH the 'reinitialize_mesh_NPT' function is being called from 'fetch_MD_cell_ingredients_restart' after calculating new Jacbdet, cell volume etc if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)||(strcmpi(pSPARC->MDMeth,"NPH") == 0) ){ @@ -3819,6 +3862,4 @@ void RestartMD(SPARC_OBJ *pSPARC) { void Rename_restart(SPARC_OBJ *pSPARC) { if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - +} \ No newline at end of file From 64171fa6ba95344ef14c4d52730254d4cc20e9f2 Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Fri, 3 Apr 2026 16:27:41 -0400 Subject: [PATCH 56/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/md.c | 70 -------------------------------------------------------- 1 file changed, 70 deletions(-) diff --git a/src/md.c b/src/md.c index 4e5c5b8b..067d5f1d 100644 --- a/src/md.c +++ b/src/md.c @@ -3399,17 +3399,6 @@ void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { // Print temperature fprintf(mdout,":TEL(K): %18.10E\n", pSPARC->elec_T); fprintf(mdout,":TIO(K): %18.10E\n", pSPARC->ion_T); - fprintf(mdout,":TELST(K): %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(mdout,":TIOST(K): %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(mdout,":PREST(Gpa): %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); - fprintf(mdout,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(mdout,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(mdout,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(mdout,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(mdout,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } fclose(mdout); } } @@ -3510,29 +3499,6 @@ void RestartMD(SPARC_OBJ *pSPARC) { fscanf(rst_fp,"%lf", &pSPARC->ion_T); else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TELST(K):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_elec_T); fscanf(rst_fp,"%lf", &pSPARC->std_elec_T); - }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); - }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); - pSPARC->mean_internal_pressure /= CONST_HA_BOHR3_GPA; pSPARC->std_internal_pressure /= CONST_HA_BOHR3_GPA; - }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); - }else if (strcmpi(str,":KENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_KE); fscanf(rst_fp,"%lf", &pSPARC->std_KE); - }else if (strcmpi(str,":FENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_PE); fscanf(rst_fp,"%lf", &pSPARC->std_PE); - }else if (strcmpi(str,":UENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_U); fscanf(rst_fp,"%lf", &pSPARC->std_U); - }else if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_Entropy); fscanf(rst_fp,"%lf", &pSPARC->std_Entropy); - } - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_TE_ext); fscanf(rst_fp,"%lf", &pSPARC->std_TE_ext); - } - } if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { if (strcmpi(str,":NPT_NH_QMASS:") == 0) { fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); @@ -3673,25 +3639,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->mean_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); @@ -3768,25 +3716,7 @@ void RestartMD(SPARC_OBJ *pSPARC) { } MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); From 63d6bdf38d2969136aa818e221870b483b1935ad Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Fri, 3 Apr 2026 18:57:37 -0400 Subject: [PATCH 57/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 16 +++++++--- src/initialization.c | 40 ++++++++++++++++++------ src/md.c | 73 ++++++++++++++++++++++++++++++++++++-------- src/readfiles.c | 6 ++++ 4 files changed, 109 insertions(+), 26 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index e1ecf20a..b14abbb0 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -867,14 +867,17 @@ typedef struct _SPARC_OBJ{ // NPT OR NPH common int NPTscaleVecs[3]; // which lattice vector can be rescaled? int NPTconstraintFlag; // confinement on side length of cell. none: no length confinement (default); 1: a:b keeps unchanged; 2: a:c keeps unchanged; - // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. + // 3: b:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. int NPT_NP_ANGLES; // Flag to decide whether changing of angles during NPT_NP ensemble is allowed - int NPHscaleVecs[3]; // Same as NPTconstraintFlag, but meant for NPH + int NPTspecialconstraint; // these are special constraint. 1: Used for graphene which allows only 2D flexibility along a and b which forms 120 degree angles between them (no change along c direction, which forms 90 degree angles with a and with b). + // Currently only 1 special constraint is supported, others will be supported in future + int NPHscaleVecs[3]; // Same as NPTscaleVecs, but meant for NPH int NPHconstraintFlag; // Same as NPTconstraintFlag, but meant for NPH - int NPH_ANGLES; // Same as NPTconstraintFlag, but meant for NPH + int NPH_ANGLES; // Same as NPT_NP_ANGLES, but meant for NPH + int NPHspecialconstraint; // Same as NPTspecialconstraint, but meant for NPH int NPTisotropicFlag; // whether it is an isotropic cell expansion; a:b:c keeps similar during NPT. // For NPT_NH, if all 3 lattive vectors are scalable, it will be an isotropic expansion; - // For NPT_NP, if all 3 lattive vectors are scalable, AND NPTconstraintFlag is 4, it will be an isotropic expansion. + double prtarget; // Target pressure of barostatic system, used in NPT_NH double scale; // length ratio of the size of cell in NPT, used in both NPT_NH double volumeCell; // volume of the cell, used in NPT_NH, NPT_NP, NPH @@ -929,7 +932,7 @@ typedef struct _SPARC_OBJ{ double NPH_bmass; // fictitious mass of barostat (bmass) used in NPT_NP double temperature; double internal_pressure; - FILE *fp_energy; + // Relaxation double Relax_fac; // Relaxation factor int elecgs_Count; // To count the number of times electronic ground state is calculated @@ -1462,11 +1465,14 @@ typedef struct _SPARC_INPUT_OBJ{ // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. int NPT_NP_ANGLES; // whether to allow for changing angles in NPT_NP, it can only be allowed (by setting to 1), when all lattice vectors can be rescaled using NPTscaleVecs: 1 2 3; // and when there are NO constraints in length confinement (so no input in NPTconstraintFlag) + int NPTspecialconstraint; // these are special constraint. 1: Used for graphene which allows only 2D flexibility along a and b which forms 120 degree angles between them (no change along c direction, which forms 90 degree angles with a and with b). + // Currently only 1 special constraint is supported, others will be supported in future int NPHscaleVecs[3]; // which lattice vector can be rescaled in NPH? int NPHconstraintFlag; // confinement on side length of cell. none: no length confinement (default); 1: a:b keeps unchanged; 2: a:c keeps unchanged; // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPH. int NPH_ANGLES; // whether to allow for changing angles in NPH, it can only be allowed (by setting to 1), when all lattice vectors can be rescaled using NPHscaleVecs: 1 2 3; // and when there are NO constraints in length confinement (so no input in NPHconstraintFlag) + int NPHspecialconstraint; double pressure_external; // Externally applied hydrostatic pressure of NPT_NP or NPH system, UNIT on input file is GPa double stress_external[6]; // Externally applied anisotropic stress tensor (applied separately from pressure_external) for NPT_NP or NPH system, UNIT on input file is GPa diff --git a/src/initialization.c b/src/initialization.c index 0d5831c9..768c5b73 100644 --- a/src/initialization.c +++ b/src/initialization.c @@ -55,7 +55,7 @@ #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) -#define N_MEMBR 217 +#define N_MEMBR 219 /** @@ -831,11 +831,13 @@ void set_defaults(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { pSPARC_Input->NPTscaleVecs[2] = 1; // default lattice vectors to be rescaled in NPT pSPARC_Input->NPTconstraintFlag = 0; // confinement on side length of cell. none: no length confinement (default) pSPARC_Input->NPT_NP_ANGLES = 0; // default: no change in angles during NPT_NP ensemble + pSPARC_Input->NPTspecialconstraint = 0; // default: no special constraint during NPT_NP ensemble pSPARC_Input->NPHscaleVecs[0] = 1; pSPARC_Input->NPHscaleVecs[1] = 1; pSPARC_Input->NPHscaleVecs[2] = 1; // default lattice vectors to be rescaled in NPH pSPARC_Input->NPHconstraintFlag = 0; // confinement on side length of cell. none: no length confinement (default) pSPARC_Input->NPH_ANGLES = 0; // default: no change in angles during NPH ensemble + pSPARC_Input->NPHspecialconstraint = 0; // default: no special constraint during NPH ensemble pSPARC_Input->NPT_NHnnos = 0; // default amount of thermo variable for NPT_NH. If MDMeth is this but nnos is 0, program will stop for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < L_QMASS; subscript_NPTNH_qmass++){ pSPARC_Input->NPT_NHqmass[subscript_NPTNH_qmass] = 0.0; @@ -1465,10 +1467,12 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { pSPARC->NPTscaleVecs[2] = pSPARC_Input->NPTscaleVecs[2]; pSPARC->NPTconstraintFlag = pSPARC_Input->NPTconstraintFlag; pSPARC->NPT_NP_ANGLES = pSPARC_Input->NPT_NP_ANGLES; + pSPARC->NPTspecialconstraint = pSPARC_Input->NPTspecialconstraint; pSPARC->NPHscaleVecs[0] = pSPARC_Input->NPHscaleVecs[0]; pSPARC->NPHscaleVecs[1] = pSPARC_Input->NPHscaleVecs[1]; pSPARC->NPHscaleVecs[2] = pSPARC_Input->NPHscaleVecs[2]; pSPARC->NPHconstraintFlag = pSPARC_Input->NPHconstraintFlag; + pSPARC->NPHspecialconstraint = pSPARC_Input->NPHspecialconstraint; pSPARC->NPH_ANGLES = pSPARC_Input->NPH_ANGLES; pSPARC->NPT_NHnnos = pSPARC_Input->NPT_NHnnos; pSPARC->ion_elec_eqT = pSPARC_Input->ion_elec_eqT; @@ -3006,10 +3010,17 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { exit(EXIT_FAILURE); } } + if (pSPARC->NPTspecialconstraint == 1){ + if (pSPARC->NPTscaleVecs[0] == 0 || pSPARC->NPTscaleVecs[1] == 0 || pSPARC->NPTscaleVecs[2] != 0) { // a or b cannot be rescaled + if (!rank) { + printf("\nNPT_SPECIAL_CONSTRAINT has conflict with NPT_SCALE_VECS! Remember lattice vector a and b needs to be rescaled, lattice vector c has to remain fixed. Also lattice vector 'c' must be orthogonal to both lattice vector a and b.\n"); + } + exit(EXIT_FAILURE); + } + } if (pSPARC->NPT_NP_ANGLES==1){ - if (pSPARC_Input->NPTscaleVecs[0] == 0 || pSPARC_Input->NPTscaleVecs[1] == 0 || pSPARC_Input->NPTscaleVecs[2] == 0 || pSPARC_Input->NPTconstraintFlag != 0){ - printf("Angle changing is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints imposed on them.\n"); - printf("To allow Angle changing, input NPT_NP_ANGLES: 1, while simultaneously NPT_SCALE_VECS: 1 2 3 and omit/skip input of NPT_SCALE_CONSTRAINTS (so default: none will be triggered) or input NPT_SCALE_CONSTRAINTS: none.\n"); + if (pSPARC_Input->NPTscaleVecs[0] == 0 || pSPARC_Input->NPTscaleVecs[1] == 0 || pSPARC_Input->NPTscaleVecs[2] == 0 || pSPARC_Input->NPTconstraintFlag != 0 || pSPARC_Input->NPTspecialconstrait != 0){ + printf("Angle changing in NPT_NP ensemble is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints of any kind imposed on them.\n"); exit(EXIT_FAILURE); } } @@ -3047,10 +3058,17 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { exit(EXIT_FAILURE); } } + if (pSPARC->NPHspecialconstraint == 1){ + if (pSPARC->NPHscaleVecs[0] == 0 || pSPARC->NPHscaleVecs[1] == 0 || pSPARC->NPHscaleVecs[2] != 0) { // a or b cannot be rescaled + if (!rank) { + printf("\nNPH_SPECIAL_CONSTRAINT has conflict with NPH_SCALE_VECS! Remember lattice vector a and b needs to be rescaled, lattice vector c has to remain fixed. Also lattice vector 'c' must be orthogonal to both lattice vector a and b.\n"); + } + exit(EXIT_FAILURE); + } + } if (pSPARC->NPH_ANGLES==1){ - if (pSPARC_Input->NPHscaleVecs[0] == 0 || pSPARC_Input->NPHscaleVecs[1] == 0 || pSPARC_Input->NPHscaleVecs[2] == 0 || pSPARC_Input->NPHconstraintFlag != 0){ - printf("Angle changing is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints imposed on them.\n"); - printf("To allow Angle changing, input NPH_ANGLES: 1, while simultaneously NPH_SCALE_VECS: 1 2 3 and omit/skip input of NPH_SCALE_CONSTRAINTS (so default: none will be triggered) or input NPH_SCALE_CONSTRAINTS: none.\n"); + if (pSPARC_Input->NPHscaleVecs[0] == 0 || pSPARC_Input->NPHscaleVecs[1] == 0 || pSPARC_Input->NPHscaleVecs[2] == 0 || pSPARC_Input->NPHconstraintFlag != 0 || pSPARC_Input->NPTspecialconstrait != 0){ + printf("Angle changing in NPH ensemble is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints of any kind imposed on them.\n"); exit(EXIT_FAILURE); } } @@ -3982,6 +4000,7 @@ void write_output_init(SPARC_OBJ *pSPARC) { else if (pSPARC->NPTconstraintFlag == 3) fprintf(output_fp," 23\n"); else if (pSPARC->NPTconstraintFlag == 4) fprintf(output_fp," 123\n"); fprintf(output_fp,"NPT_NP_ANGLES: %d\n",pSPARC->NPT_NP_ANGLES); + fprintf(output_fp,"NPT_NP_SPECIAL_CONSTRAINT: %d\n",pSPARC->NPTspecialconstraint); fprintf(output_fp,"NPT_NP_QMASS: %.15g\n",pSPARC->NPT_NP_qmass); fprintf(output_fp,"NPT_NP_BMASS: %.15g\n",pSPARC->NPT_NP_bmass); fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->pressure_external+pSPARC->stress_external[0] @@ -4005,6 +4024,7 @@ void write_output_init(SPARC_OBJ *pSPARC) { else if (pSPARC->NPHconstraintFlag == 3) fprintf(output_fp," 23\n"); else if (pSPARC->NPHconstraintFlag == 4) fprintf(output_fp," 123\n"); fprintf(output_fp,"NPH_ANGLES: %d\n",pSPARC->NPH_ANGLES); + fprintf(output_fp,"NPH_SPECIAL_CONSTRAINT: %d\n",pSPARC->NPHspecialconstraint); fprintf(output_fp,"NPH_BMASS: %.15g\n",pSPARC->NPH_bmass); fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->pressure_external+pSPARC->stress_external[0] ,pSPARC->pressure_external+pSPARC->stress_external[1] @@ -4442,7 +4462,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, - MPI_INT, MPI_INT, /* int */ + MPI_INT, MPI_INT, MPI_INT, MPI_INT, /* int */ MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, /* double array */ @@ -4488,7 +4508,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1,/* int */ + 1, 1, 1, 1, /* int */ 9, 3, L_QMASS, L_kpoint, L_kpoint, L_kpoint, 6, 6,/* double array */ 1, 1, 1, 1, 1, @@ -4601,6 +4621,8 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_Get_address(&sparc_input_tmp.NPHconstraintFlag, addr + i++); MPI_Get_address(&sparc_input_tmp.NPT_NP_ANGLES, addr + i++); MPI_Get_address(&sparc_input_tmp.NPH_ANGLES, addr + i++); + MPI_Get_address(&sparc_input_tmp.NPTspecialconstraint, addr + i++); + MPI_Get_address(&sparc_input_tmp.NPHspecialconstraint, addr + i++); MPI_Get_address(&sparc_input_tmp.MAXIT_FOCK, addr + i++); MPI_Get_address(&sparc_input_tmp.ExxAcc, addr + i++); MPI_Get_address(&sparc_input_tmp.ExxMemBatch, addr + i++); diff --git a/src/md.c b/src/md.c index 067d5f1d..3221f4c3 100644 --- a/src/md.c +++ b/src/md.c @@ -1773,6 +1773,7 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ } pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); //Update Ionic temperature; } @@ -1922,18 +1923,20 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min double internal_stress_cartesian[9]; //Initialize some useful constants - double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]={0}; + double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]={0}; int NPT_NPHspecialconstraint; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; - + NPT_NPHspecialconstraint = pSPARC->NPTspecialconstraint; + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } else{ NPT_NPH_ANGLES = pSPARC->NPH_ANGLES; NPT_NPHconstraintFlag = pSPARC->NPHconstraintFlag; NPT_NPHscaleVecs[0] = pSPARC->NPHscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPHscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPHscaleVecs[2]; + NPT_NPHspecialconstraint = pSPARC->NPHspecialconstraint; baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } @@ -2013,13 +2016,13 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs, NPT_NPHspecialconstraint); } } else { if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs, NPT_NPHspecialconstraint); } } @@ -2031,7 +2034,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min } //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0){ + if ( NPT_NPHspecialconstraint == 1 ){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; @@ -2208,7 +2211,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min Update_metric_tensor_momenta_iteratively_half_step(pSPARC); //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0){ + if ( NPT_NPHspecialconstraint == 1 ){ pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; @@ -2322,12 +2325,13 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; pSPARC->SNOSE[0] = S_new; } + pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); //Update Ionic temperature; // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// } - -void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs){ +// IF and When this function is called, it imposes a universal constraint of all angles between lattice vectors being FIXED; on top of other constraints explicitly imposed in the function through 'if' condition +void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs, int *NPT_NPHspecialconstraint){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants @@ -2368,10 +2372,31 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int else if (NPT_NPHconstraintFlag == 1){ gpig[0] = (gpig[0] + gpig[4]) / 2; gpig[4] = gpig[0]; + if (NPT_NPHscaleVecs[2] == 0){ + gpig[8] = 0; + } + } + + // |a| = |c| and |b| can vary independently; and all angles between lattice vectors are FIXED + else if (NPT_NPHconstraintFlag == 2){ + gpig[0] = (gpig[0] + gpig[8]) / 2; + gpig[8] = gpig[0]; + if (NPT_NPHscaleVecs[1] == 0){ + gpig[4] = 0; + } + } + + // |b| = |c| and |a| can vary independently; and all angles between lattice vectors are FIXED + else if (NPT_NPHconstraintFlag == 3){ + gpig[4] = (gpig[4] + gpig[8]) / 2; + gpig[8] = gpig[4]; + if (NPT_NPHscaleVecs[0] == 0){ + gpig[0] = 0; + } } // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (NPT_NPHscaleVecs[2] == 0 ){ + else if ( NPT_NPHspecialconstraint==1 ){ gpig[8] = 0; gpig[7] = 0; gpig[6] = 0; @@ -2379,16 +2404,30 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int gpig[2] = 0; } - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + //Only |c| varies, |a| and |b| are fixed + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ gpig[0] = 0; gpig[4] = 0; } + //Only |a| varies, |b| and |c| are fixed + else if (NPT_NPHscaleVecs[0] == 1 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 0){ + gpig[4] = 0; + gpig[8] = 0; + } + + //Only |b| varies, |a| and |c| are fixed + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 1 && NPT_NPHscaleVecs[2] == 0){ + gpig[0] = 0; + gpig[8] = 0; + } + constraint_velocity[0] = gpig[0] * baro_const4; constraint_velocity[4] = gpig[4] * baro_const4; constraint_velocity[8] = gpig[8] * baro_const4; + //Impose the constraint on angles being FIXED constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; @@ -2501,6 +2540,16 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do new_metric_tensor[4] = new_metric_tensor[0]; } + else if (NPT_NPHconstraintFlag == 2){ + new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[8] ) / 2.0; + new_metric_tensor[8] = new_metric_tensor[0]; + } + + else if (NPT_NPHconstraintFlag == 3){ + new_metric_tensor[4] = ( new_metric_tensor[4] + new_metric_tensor[8] ) / 2.0; + new_metric_tensor[8] = new_metric_tensor[4]; + } + a_norm = sqrt( new_metric_tensor[0] ); b_norm = sqrt( new_metric_tensor[4] ); c_norm = sqrt( new_metric_tensor[8] ); @@ -3077,10 +3126,10 @@ void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old, mean_total_internal_stress_old[9]; int Count; if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ - Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; + Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; } else{ - Count = pSPARC->MDCount + pSPARC->restartCount; + Count = pSPARC->MDCount; } mean_Te_old = pSPARC->mean_elec_T; mean_Ti_old = pSPARC->mean_ion_T; diff --git a/src/readfiles.c b/src/readfiles.c index 53bb4840..abdfcd83 100644 --- a/src/readfiles.c +++ b/src/readfiles.c @@ -780,6 +780,9 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } else if (strcmpi(str,"NPT_NP_ANGLES:") == 0){ fscanf(input_fp,"%d",&pSPARC_Input->NPT_NP_ANGLES); fscanf(input_fp, "%*[^\n]\n"); + } else if (strcmpi(str,"NPT_SPECIAL_CONSTRAINT:") == 0){ + fscanf(input_fp,"%d",&pSPARC_Input->NPTspecialconstraint); + fscanf(input_fp, "%*[^\n]\n"); } else if (strcmpi(str,"NPH_SCALE_VECS:") == 0) { int dir[3] = {0, 0, 0}; pSPARC_Input->NPHscaleVecs[0] = 0; pSPARC_Input->NPHscaleVecs[1] = 0; pSPARC_Input->NPHscaleVecs[2] = 0; @@ -822,6 +825,9 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } else if (strcmpi(str,"NPH_ANGLES:") == 0){ fscanf(input_fp,"%d",&pSPARC_Input->NPH_ANGLES); fscanf(input_fp, "%*[^\n]\n"); + } else if (strcmpi(str,"NPH_SPECIAL_CONSTRAINT:") == 0){ + fscanf(input_fp,"%d",&pSPARC_Input->NPHspecialconstraint); + fscanf(input_fp, "%*[^\n]\n"); } else if (strcmpi(str,"NPT_NH_QMASS:") == 0) { fscanf(input_fp,"%d",&pSPARC_Input->NPT_NHnnos); for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC_Input->NPT_NHnnos; subscript_NPTNH_qmass++){ From fd755637a69b2f91309016e4787e3e4580128aeb Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Fri, 3 Apr 2026 21:23:28 -0400 Subject: [PATCH 58/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/initialization.c | 8 ++++---- src/md.c | 44 +++++++++++++++++++++++++++++++++++++++++--- src/readfiles.c | 2 +- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/initialization.c b/src/initialization.c index 768c5b73..4f14e52b 100644 --- a/src/initialization.c +++ b/src/initialization.c @@ -3011,7 +3011,7 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { } } if (pSPARC->NPTspecialconstraint == 1){ - if (pSPARC->NPTscaleVecs[0] == 0 || pSPARC->NPTscaleVecs[1] == 0 || pSPARC->NPTscaleVecs[2] != 0) { // a or b cannot be rescaled + if (pSPARC->NPTscaleVecs[0] == 0 || pSPARC->NPTscaleVecs[1] == 0 || pSPARC->NPTscaleVecs[2] != 0) { // a or b cannot be rescaled or c is being rescaled if (!rank) { printf("\nNPT_SPECIAL_CONSTRAINT has conflict with NPT_SCALE_VECS! Remember lattice vector a and b needs to be rescaled, lattice vector c has to remain fixed. Also lattice vector 'c' must be orthogonal to both lattice vector a and b.\n"); } @@ -3019,7 +3019,7 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { } } if (pSPARC->NPT_NP_ANGLES==1){ - if (pSPARC_Input->NPTscaleVecs[0] == 0 || pSPARC_Input->NPTscaleVecs[1] == 0 || pSPARC_Input->NPTscaleVecs[2] == 0 || pSPARC_Input->NPTconstraintFlag != 0 || pSPARC_Input->NPTspecialconstrait != 0){ + if (pSPARC_Input->NPTscaleVecs[0] == 0 || pSPARC_Input->NPTscaleVecs[1] == 0 || pSPARC_Input->NPTscaleVecs[2] == 0 || pSPARC_Input->NPTconstraintFlag != 0 || pSPARC_Input->NPTspecialconstraint != 0){ printf("Angle changing in NPT_NP ensemble is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints of any kind imposed on them.\n"); exit(EXIT_FAILURE); } @@ -3059,7 +3059,7 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { } } if (pSPARC->NPHspecialconstraint == 1){ - if (pSPARC->NPHscaleVecs[0] == 0 || pSPARC->NPHscaleVecs[1] == 0 || pSPARC->NPHscaleVecs[2] != 0) { // a or b cannot be rescaled + if (pSPARC->NPHscaleVecs[0] == 0 || pSPARC->NPHscaleVecs[1] == 0 || pSPARC->NPHscaleVecs[2] != 0) { // a or b cannot be rescaled or c is being rescaled if (!rank) { printf("\nNPH_SPECIAL_CONSTRAINT has conflict with NPH_SCALE_VECS! Remember lattice vector a and b needs to be rescaled, lattice vector c has to remain fixed. Also lattice vector 'c' must be orthogonal to both lattice vector a and b.\n"); } @@ -3067,7 +3067,7 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { } } if (pSPARC->NPH_ANGLES==1){ - if (pSPARC_Input->NPHscaleVecs[0] == 0 || pSPARC_Input->NPHscaleVecs[1] == 0 || pSPARC_Input->NPHscaleVecs[2] == 0 || pSPARC_Input->NPHconstraintFlag != 0 || pSPARC_Input->NPTspecialconstrait != 0){ + if (pSPARC_Input->NPHscaleVecs[0] == 0 || pSPARC_Input->NPHscaleVecs[1] == 0 || pSPARC_Input->NPHscaleVecs[2] == 0 || pSPARC_Input->NPHconstraintFlag != 0 || pSPARC_Input->NPHspecialconstraint != 0){ printf("Angle changing in NPH ensemble is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints of any kind imposed on them.\n"); exit(EXIT_FAILURE); } diff --git a/src/md.c b/src/md.c index 3221f4c3..d8034123 100644 --- a/src/md.c +++ b/src/md.c @@ -1929,7 +1929,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; NPT_NPHspecialconstraint = pSPARC->NPTspecialconstraint; - + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } else{ @@ -2041,10 +2041,27 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min pSPARC->Pm_metric_tensor[5] = 0; pSPARC->Pm_metric_tensor[2] = 0; } - if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } + //Only |c| varies, |a| and |b| are fixed + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + + //Only |a| varies, |b| and |c| are fixed + else if (NPT_NPHscaleVecs[0] == 1 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 0){ + gpig[4] = 0; + gpig[8] = 0; + } + + //Only |b| varies, |a| and |c| are fixed + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 1 && NPT_NPHscaleVecs[2] == 0){ + gpig[0] = 0; + gpig[8] = 0; + } cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); @@ -2218,10 +2235,31 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min pSPARC->Pm_metric_tensor[5] = 0; pSPARC->Pm_metric_tensor[2] = 0; } - if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ pSPARC->Pm_metric_tensor[0] = 0; pSPARC->Pm_metric_tensor[4] = 0; } + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[4] = 0; + } + //Only |c| varies, |a| and |b| are fixed + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ + gpig[0] = 0; + gpig[4] = 0; + } + + //Only |a| varies, |b| and |c| are fixed + else if (NPT_NPHscaleVecs[0] == 1 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 0){ + gpig[4] = 0; + gpig[8] = 0; + } + + //Only |b| varies, |a| and |c| are fixed + else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 1 && NPT_NPHscaleVecs[2] == 0){ + gpig[0] = 0; + gpig[8] = 0; + } diff --git a/src/readfiles.c b/src/readfiles.c index abdfcd83..db0c853a 100644 --- a/src/readfiles.c +++ b/src/readfiles.c @@ -780,7 +780,7 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } else if (strcmpi(str,"NPT_NP_ANGLES:") == 0){ fscanf(input_fp,"%d",&pSPARC_Input->NPT_NP_ANGLES); fscanf(input_fp, "%*[^\n]\n"); - } else if (strcmpi(str,"NPT_SPECIAL_CONSTRAINT:") == 0){ + } else if (strcmpi(str,"NPT_NP_SPECIAL_CONSTRAINT:") == 0){ fscanf(input_fp,"%d",&pSPARC_Input->NPTspecialconstraint); fscanf(input_fp, "%*[^\n]\n"); } else if (strcmpi(str,"NPH_SCALE_VECS:") == 0) { From 90b01370eb269409d5e524b85a9ab160c18e2dc0 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sat, 4 Apr 2026 16:27:32 -0400 Subject: [PATCH 59/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- doc/.LaTeX/MD.tex | 282 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 272 insertions(+), 10 deletions(-) diff --git a/doc/.LaTeX/MD.tex b/doc/.LaTeX/MD.tex index c90c0305..a76fc10a 100644 --- a/doc/.LaTeX/MD.tex +++ b/doc/.LaTeX/MD.tex @@ -72,7 +72,7 @@ \end{columns} \begin{block}{Description} -Type of QMD to be performed. Currently, NVE (microcanonical ensemble), NVT\_NH (canonical ensemble with Nose-Hoover thermostat), NVK\_G (isokinetic ensemble with Gaussian thermostat), NPT\_NH (isothermal-isobaric ensemble with Nose-Hoover thermostat) and NPT\_NP (isothermal-isobaric ensemble with Nose-Poincare thermostat) are supported. +Type of QMD to be performed. Currently, NVE (microcanonical ensemble), NVT\_NH (canonical ensemble with Nose-Hoover thermostat), NVK\_G (isokinetic ensemble with Gaussian thermostat), NPT\_NH (isothermal-isobaric ensemble with Nose-Hoover thermostat), NPT\_NP (isothermal-isobaric ensemble with Nose-Poincare thermostat) and NPH (isothermal-isoenthalpic ensemble) are supported. \end{block} \end{frame} @@ -466,7 +466,7 @@ \begin{block}{Remark} Applicable to NPT\_NP \hyperlink{MD_METHOD}{\texttt{MD\_METHOD}} only. -Program will exit if NPT\_NP is selected but NPT\_NP\_BMASS is not input +Program will exit if NPT\_NP is selected but NPT\_NP\_QMASS is not input \end{block} \end{frame} @@ -537,7 +537,6 @@ \begin{block}{Description} Specify which lattice vectors can be rescaled in NPT\_NH and NPT\_NP. The cell will only expand or shrink in the specified directions. -Rescaled vectors can be specified for orthogonal systems if NPT\_NP thermostat is used. \end{block} \begin{block}{Remark} @@ -545,7 +544,7 @@ If it is set in NPT\_NH, the expansion or shrinkage on designated lattice vector will try to keep the total pressure to oscillate near the target pressure. -If it is set in NPT\_NP, the expansion or shrinkage on designated lattice vector will only try to keep the normal stress at their direction to oscillate near the target pressure. +If it is set in NPT\_NP, the expansion or shrinkage on designated lattice vector will only try to keep the normal stress at their direction to oscillate near the corresponding target stress component (which is the sum of external pressure and corresponding external stress component). \end{block} \end{frame} @@ -559,7 +558,7 @@ \begin{columns} \column{0.4\linewidth} \begin{block}{Type} -Double +Int \end{block} \begin{block}{Default} @@ -577,12 +576,162 @@ \end{columns} \begin{block}{Description} -Set the scale constraint for lattice vectors in NPT\_NP. The length ratio between the designated lattice vector keeps constant in NPT\_NP thermostat. For example, if ``12'' is set, then the length ratio between 1st and 2nd lattice vectors will keep constant. +Set the scale constraint for lattice vectors in NPT\_NP. The length ratio between the designated lattice vector keeps constant in NPT\_NP ensemble. For example, if ``12'' is set, then the length ratio between 1st and 2nd lattice vectors will keep constant. \end{block} \begin{block}{Remark} -Applicable to orthogonal system using NPT\_NP \hyperlink{MD_METHOD}{\texttt{MD\_METHOD}} only. +Applicable to NPT\_NP \hyperlink{MD_METHOD}{\texttt{MD\_METHOD}} only. + +There are 4 types of available constraints. ``12'' or ``21''; ``13'' or ``31''; ``23'' or ``32''; ``123'' or ``132'' or ``213'' or ``231'' or ``312'' or ``321''. +\end{block} + +\end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{frame}[allowframebreaks]{\texttt{NPT\_NP\_ANGLES}} \label{NPT_NP_ANGLES} +\vspace*{-12pt} +\begin{columns} +\column{0.4\linewidth} +\begin{block}{Type} +Int +\end{block} + +\begin{block}{Default} +0 +\end{block} + +\column{0.4\linewidth} +\begin{block}{Unit} +No unit +\end{block} + +\begin{block}{Example} +\texttt{NPT\_SCALE\_CONSTRAINTS}: 1 +\end{block} +\end{columns} + +\begin{block}{Description} +Flag to determine whether to allow changing of angles of the cell (simulation box) in NPT\_NP. Choosing "1" as the input allows changing of angles between lattice vectors, and "0" keeps the angles between lattice vectors to be fixed. +\end{block} + +\begin{block}{Remark} +Applicable to NPT\_NP \hyperlink{MD_METHOD}{\texttt{MD\_METHOD}} only when all the lattice vectors are allowed to be rescaled by setting \hyperlink{NPT\_SCALE\_VECS}{\texttt{NPT\_SCALE\_VECS}} to "123" and simultaneously no other constraints are imposed through \hyperlink{NPT\_SCALE\_CONSTRAINTS}{\texttt{NPT\_SCALE\_CONSTRAINTS}}. +\end{block} + +\end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{frame}[allowframebreaks]{\texttt{NPH\_BMASS}} \label{NPH_BMASS} +\vspace*{-12pt} +\begin{columns} +\column{0.4\linewidth} +\begin{block}{Type} +Double +\end{block} + +\begin{block}{Default} +No default value +\end{block} + +\column{0.4\linewidth} +\begin{block}{Unit} +atomic unit +\end{block} + +\begin{block}{Example} +\texttt{NPH\_BMASS}: 72.4 +\end{block} +\end{columns} + +\begin{block}{Description} +Gives the inertia mass for the barostat variable in NPH. +\end{block} + +\begin{block}{Remark} +Applicable to NPH \hyperlink{MD_METHOD}{\texttt{MD\_METHOD}} only. +Program will exit if NPH is selected but NPH\_BMASS is not input. +\end{block} + +\end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{frame}[allowframebreaks]{\texttt{NPH\_SCALE\_VECS}} \label{NPH_SCALE_VECS} +\vspace*{-12pt} +\begin{columns} +\column{0.4\linewidth} +\begin{block}{Type} +Int +\end{block} + +\begin{block}{Default} +1 2 3 +\end{block} + +\column{0.4\linewidth} +\begin{block}{Unit} +No unit +\end{block} + +\begin{block}{Example} +\texttt{NPH\_SCALE\_VECS}: 1 2 +\end{block} +\end{columns} + +\begin{block}{Description} +Specify which lattice vectors can be rescaled in NPH. The cell will only expand or shrink in the specified directions. + +\end{block} + +\begin{block}{Remark} +It is similar to \hyperlink{NPT\_SCALE\_VECS}{\texttt{NPT\_SCALE\_VECS}} but meant to use when doing NPH ensemble. Only three numbers 1, 2 and 3 can be accepted. For example, if ``2 3'' is the input, the cell will only expand or shrink in the directions of lattice vector 2 and lattice vector 3. +\\ +If it is set in NPH, the expansion or shrinkage on designated lattice vector will only try to keep the total internal normal stress at their direction to oscillate near the corresponding target stress component (which is the sum of external pressure and corresponding external stress component). +\end{block} + +\end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{frame}[allowframebreaks]{\texttt{NPH\_SCALE\_CONSTRAINTS}} \label{NPH_SCALE_CONSTRAINTS} +\vspace*{-12pt} +\begin{columns} +\column{0.4\linewidth} +\begin{block}{Type} +Int +\end{block} +\begin{block}{Default} +none +\end{block} + +\column{0.4\linewidth} +\begin{block}{Unit} +No unit +\end{block} + +\begin{block}{Example} +\texttt{NPH\_SCALE\_CONSTRAINTS}: 23 +\end{block} +\end{columns} + +\begin{block}{Description} +Set the scale constraint for lattice vectors in NPH. The length ratio between the designated lattice vector keeps constant in NPH thermostat. For example, if ``23'' is set, then the length ratio between 2nd and 3rd lattice vectors will be kept constant. +\end{block} + +\begin{block}{Remark} +Applicable to NPH \hyperlink{MD_METHOD}{\texttt{MD\_METHOD}} only. +It is similar to \hyperlink{NPT\_SCALE\_VECS}{\texttt{NPT\_SCALE\_VECS}} but meant to use when doing NPH ensemble. There are 4 types of available constraints. ``12'' or ``21''; ``13'' or ``31''; ``23'' or ``32''; ``123'' or ``132'' or ``213'' or ``231'' or ``312'' or ``321''. \end{block} @@ -591,6 +740,43 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{frame}[allowframebreaks]{\texttt{NPH\_ANGLES}} \label{NPH_ANGLES} +\vspace*{-12pt} +\begin{columns} +\column{0.4\linewidth} +\begin{block}{Type} +Int +\end{block} + +\begin{block}{Default} +0 +\end{block} + +\column{0.4\linewidth} +\begin{block}{Unit} +No unit +\end{block} + +\begin{block}{Example} +\texttt{NPT\_SCALE\_CONSTRAINTS}: 1 +\end{block} +\end{columns} + +\begin{block}{Description} +Flag to determine whether to allow changing of angles of the cell (simulation box) in NPH. Choosing "1" as the input allows changing of angles between lattice vectors, and "0" keeps the angles between lattice vectors to be fixed. +\end{block} + +\begin{block}{Remark} +Applicable to NPH \hyperlink{MD_METHOD}{\texttt{MD\_METHOD}} only when all the lattice vectors are allowed to be rescaled by setting \hyperlink{NPH\_SCALE\_VECS}{\texttt{NPH\_SCALE\_VECS}} to "123" and simultaneously no other constraints are imposed through \hyperlink{NPH\_SCALE\_CONSTRAINTS}{\texttt{NPH\_SCALE\_CONSTRAINTS}}. +\end{block} + +\end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[allowframebreaks]{\texttt{TARGET\_PRESSURE}} \label{TARGET_PRESSURE} \vspace*{-12pt} @@ -615,11 +801,87 @@ \end{columns} \begin{block}{Description} -Gives the outer pressure in NPT\_NH and NPT\_NP. +Gives the outer pressure in NPT\_NH. \end{block} \begin{block}{Remark} -Applicable to NPT\_NH and NPT\_NP \hyperlink{MD_METHOD}{\texttt{MD\_METHOD}} only. +Applicable to NPT\_NH \hyperlink{MD_METHOD}{\texttt{MD\_METHOD}} only. +\end{block} + +\end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{frame}[allowframebreaks]{\texttt{EXTERNAL\_PRESSURE}} \label{EXTERNAL_PRESSURE} +\vspace*{-12pt} +\begin{columns} +\column{0.4\linewidth} +\begin{block}{Type} +Double +\end{block} + +\begin{block}{Default} +0.0 +\end{block} + +\column{0.4\linewidth} +\begin{block}{Unit} +GPa +\end{block} + +\begin{block}{Example} +\texttt{EXTERNAL\_PRESSURE}: 0.5 +\end{block} +\end{columns} + +\begin{block}{Description} +Gives the outer/external pressure in NPT\_NP and NPH. +\end{block} + +\begin{block}{Remark} +Applicable to NPT\_NP and NPH \hyperlink{MD_METHOD}{\texttt{MD\_METHOD}} only. In contrast to NPT\_NH governed by a single \hyperlink{TARGET\_PRESSURE}{\texttt{TARGET\_PRESSURE}} argument, the NPT\_NP and NPH are governed by two arguments: \hyperlink{EXTERNAL\_PRESSURE}{\texttt{EXTERNAL\_PRESSURE}} and \hyperlink{EXTERNAL\_STRESS}{\texttt{EXTERNAL\_STRESS}}, the sum of which gives target stress, around which the total internal stress must oscillate. +\\ +Note that in absence of \hyperlink{EXTERNAL_STRESS}{\texttt{EXTERNAL\_STRESS}}, target stress in NPT\_NP and NPH would be isotropic and (have diagonal components) equal to \hyperlink{EXTERNAL\_PRESSURE}{\texttt{EXTERNAL\_PRESSURE}}. + + +\end{block} + +\end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{frame}[allowframebreaks]{\texttt{EXTERNAL\_STRESS}} \label{EXTERNAL_STRESS} +\vspace*{-12pt} +\begin{columns} +\column{0.4\linewidth} +\begin{block}{Type} +Double +\end{block} + +\begin{block}{Default} +0.0 0.0 0.0 0.0 0.0 0.0 +\end{block} + +\column{0.4\linewidth} +\begin{block}{Unit} +GPa +\end{block} + +\begin{block}{Example} +\texttt{EXTERNAL\_STRESS}: \\ 5 0.1 -5 2 4 0.3 +\end{block} +\end{columns} + +\begin{block}{Description} +Gives the outer stress in NPT\_NP and NPH. +\end{block} + +\begin{block}{Remark} +Applicable to NPT\_NP and NPH \hyperlink{MD_METHOD}{\texttt{MD\_METHOD}} only. The format is "$\sigma_{xx} \ \sigma_{yy} \ \sigma_{zz} \ \sigma_{xy} \ \sigma_{xz} \ \sigma_{yz}$", where $\sigma$ here denotes the \hyperlink{EXTERNAL\_PRESSURE}{\texttt{EXTERNAL\_PRESSURE}}. The target stress around which the total internal stress must oscillate in NPT\_NP and NPH ensemble is the sum of \hyperlink{EXTERNAL\_PRESSURE}{\texttt{EXTERNAL\_PRESSURE}} and \hyperlink{EXTERNAL\_STRESS}{\texttt{EXTERNAL\_STRESS}}. \end{block} \end{frame} @@ -692,4 +954,4 @@ \end{block} \end{frame} -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% From 463ffc844c5295279b899b51ed46bf667e1ebef3 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sat, 4 Apr 2026 17:12:27 -0400 Subject: [PATCH 60/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- ChangeLog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ChangeLog b/ChangeLog index d4c1819e..830ebdf8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,15 @@ -Name -changes +-------------- +April 04, 2026 +Name: Shubhang Krishnakant Trivedi +Changes: (src/md.c, src/initialization.c, src/readfiles.c, src/include/md.h, src/include/isddft.h) +1. Extended the functionality of NPT_NP QMD for doing full cell flexibility (including changing of cell angles). +2. Added the NPH (isobaric-isoenthalpic) ensemble in QMD with allowing full cell flexibility. +3. Updated the manual regarding the same. +4. Added extra tests corresponding to the same. + -------------- December 03, 2025 Name: Sayan Bhowmik From af1236a67e2f9b0ebbd07877c5a145b51f363b51 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 15:22:20 -0400 Subject: [PATCH 61/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 830ebdf8..da7c0dcd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,7 @@ -changes -------------- -April 04, 2026 +April 05, 2026 Name: Shubhang Krishnakant Trivedi Changes: (src/md.c, src/initialization.c, src/readfiles.c, src/include/md.h, src/include/isddft.h) 1. Extended the functionality of NPT_NP QMD for doing full cell flexibility (including changing of cell angles). From 8d6a9aa019f108fbb69644937c18fc400cef92f3 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 15:41:12 -0400 Subject: [PATCH 62/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- tests/SPARC_testing_script.py | 64 +++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/tests/SPARC_testing_script.py b/tests/SPARC_testing_script.py index 2bf461fb..82dc266a 100644 --- a/tests/SPARC_testing_script.py +++ b/tests/SPARC_testing_script.py @@ -202,37 +202,87 @@ ################################################################################################################## SYSTEMS["systemname"].append('Al18Si18_NPTNH') SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_npt']) +SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nptnh']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################ SYSTEMS["systemname"].append('Al16Si16_NPTNH_restart') SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_npt']) +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnh']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################ SYSTEMS["systemname"].append('Al18Si18_NPTNH_lat23') SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_npt']) +SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nptnh']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################ SYSTEMS["systemname"].append('Al18Si18_NPTNP') SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_npt']) +SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################ SYSTEMS["systemname"].append('Al16Si16_NPTNP_restart') SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_npt']) +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## SYSTEMS["systemname"].append('Al18C2_NPTNP_aeqb_c') SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_npt']) +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## SYSTEMS["systemname"].append('Al18C2_NPTNP_onlyc') SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_npt']) +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) +SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) +################################################################################################################## +SYSTEMS["systemname"].append('Al18C2_NPTNP_aeqb_ortho_c') +SYSTEMS["directory"].append("./") +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) +SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) +################################################################################################################## +SYSTEMS["systemname"].append('Al18C2_NPTNP_ortho_c') +SYSTEMS["directory"].append("./") +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) +SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) +################################################################################################################## +SYSTEMS["systemname"].append('Al18C2_NPTNP_fullflex') +SYSTEMS["directory"].append("./") +SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nptnp']) +SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) +################################################################################################################ +SYSTEMS["systemname"].append('Al18Si18_NPH') +SYSTEMS["directory"].append("./") +SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nph']) +SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) +################################################################################################################ +SYSTEMS["systemname"].append('Al16Si16_NPH_restart') +SYSTEMS["directory"].append("./") +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) +SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) +################################################################################################################## +SYSTEMS["systemname"].append('Al18C2_NPH_aeqc_b') +SYSTEMS["directory"].append("./") +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) +SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) +################################################################################################################## +SYSTEMS["systemname"].append('Al18C2_NPH_onlyb') +SYSTEMS["directory"].append("./") +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) +SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) +################################################################################################################## +SYSTEMS["systemname"].append('Al18C2_NPH_beqc_ortho_a') +SYSTEMS["directory"].append("./") +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) +SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) +################################################################################################################## +SYSTEMS["systemname"].append('Al18C2_NPH_ortho_a') +SYSTEMS["directory"].append("./") +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) +SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) +################################################################################################################## +SYSTEMS["systemname"].append('Al18C2_NPH_fullflex') +SYSTEMS["directory"].append("./") +SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nph']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## SYSTEMS["systemname"].append('Au_wire_d3') From 75b44ceb5f6429832ef6395618e134eb4ef49fb9 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 15:48:31 -0400 Subject: [PATCH 63/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- tests/SPARC_testing_script.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/SPARC_testing_script.py b/tests/SPARC_testing_script.py index 82dc266a..aafc3613 100644 --- a/tests/SPARC_testing_script.py +++ b/tests/SPARC_testing_script.py @@ -245,7 +245,7 @@ SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## -SYSTEMS["systemname"].append('Al18C2_NPTNP_fullflex') +SYSTEMS["systemname"].append('Al18C2_NPTNP_full_flex') SYSTEMS["directory"].append("./") SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) @@ -280,7 +280,7 @@ SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## -SYSTEMS["systemname"].append('Al18C2_NPH_fullflex') +SYSTEMS["systemname"].append('Al18C2_NPH_full_flex') SYSTEMS["directory"].append("./") SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nph']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) From 5bfac137e8a549a7102730d58d4bef5027743b5e Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 16:45:58 -0400 Subject: [PATCH 64/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- tests/SPARC_testing_script.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/SPARC_testing_script.py b/tests/SPARC_testing_script.py index aafc3613..de849256 100644 --- a/tests/SPARC_testing_script.py +++ b/tests/SPARC_testing_script.py @@ -227,7 +227,7 @@ ################################################################################################################## SYSTEMS["systemname"].append('Al18C2_NPTNP_aeqb_c') SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) +SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## SYSTEMS["systemname"].append('Al18C2_NPTNP_onlyc') @@ -262,7 +262,7 @@ ################################################################################################################## SYSTEMS["systemname"].append('Al18C2_NPH_aeqc_b') SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) +SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nph']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## SYSTEMS["systemname"].append('Al18C2_NPH_onlyb') From 04cc34eb17ddc894d840905cb4ce5bcb28b29b63 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:11:37 -0400 Subject: [PATCH 65/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/initialization.c | 34 +---- src/md.c | 349 ++++++++++++++++++++----------------------- src/readfiles.c | 6 - 3 files changed, 168 insertions(+), 221 deletions(-) diff --git a/src/initialization.c b/src/initialization.c index 4f14e52b..b27d95c4 100644 --- a/src/initialization.c +++ b/src/initialization.c @@ -55,7 +55,7 @@ #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) -#define N_MEMBR 219 +#define N_MEMBR 217 /** @@ -831,13 +831,11 @@ void set_defaults(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { pSPARC_Input->NPTscaleVecs[2] = 1; // default lattice vectors to be rescaled in NPT pSPARC_Input->NPTconstraintFlag = 0; // confinement on side length of cell. none: no length confinement (default) pSPARC_Input->NPT_NP_ANGLES = 0; // default: no change in angles during NPT_NP ensemble - pSPARC_Input->NPTspecialconstraint = 0; // default: no special constraint during NPT_NP ensemble pSPARC_Input->NPHscaleVecs[0] = 1; pSPARC_Input->NPHscaleVecs[1] = 1; pSPARC_Input->NPHscaleVecs[2] = 1; // default lattice vectors to be rescaled in NPH pSPARC_Input->NPHconstraintFlag = 0; // confinement on side length of cell. none: no length confinement (default) pSPARC_Input->NPH_ANGLES = 0; // default: no change in angles during NPH ensemble - pSPARC_Input->NPHspecialconstraint = 0; // default: no special constraint during NPH ensemble pSPARC_Input->NPT_NHnnos = 0; // default amount of thermo variable for NPT_NH. If MDMeth is this but nnos is 0, program will stop for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < L_QMASS; subscript_NPTNH_qmass++){ pSPARC_Input->NPT_NHqmass[subscript_NPTNH_qmass] = 0.0; @@ -1467,12 +1465,10 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { pSPARC->NPTscaleVecs[2] = pSPARC_Input->NPTscaleVecs[2]; pSPARC->NPTconstraintFlag = pSPARC_Input->NPTconstraintFlag; pSPARC->NPT_NP_ANGLES = pSPARC_Input->NPT_NP_ANGLES; - pSPARC->NPTspecialconstraint = pSPARC_Input->NPTspecialconstraint; pSPARC->NPHscaleVecs[0] = pSPARC_Input->NPHscaleVecs[0]; pSPARC->NPHscaleVecs[1] = pSPARC_Input->NPHscaleVecs[1]; pSPARC->NPHscaleVecs[2] = pSPARC_Input->NPHscaleVecs[2]; pSPARC->NPHconstraintFlag = pSPARC_Input->NPHconstraintFlag; - pSPARC->NPHspecialconstraint = pSPARC_Input->NPHspecialconstraint; pSPARC->NPH_ANGLES = pSPARC_Input->NPH_ANGLES; pSPARC->NPT_NHnnos = pSPARC_Input->NPT_NHnnos; pSPARC->ion_elec_eqT = pSPARC_Input->ion_elec_eqT; @@ -3010,16 +3006,8 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { exit(EXIT_FAILURE); } } - if (pSPARC->NPTspecialconstraint == 1){ - if (pSPARC->NPTscaleVecs[0] == 0 || pSPARC->NPTscaleVecs[1] == 0 || pSPARC->NPTscaleVecs[2] != 0) { // a or b cannot be rescaled or c is being rescaled - if (!rank) { - printf("\nNPT_SPECIAL_CONSTRAINT has conflict with NPT_SCALE_VECS! Remember lattice vector a and b needs to be rescaled, lattice vector c has to remain fixed. Also lattice vector 'c' must be orthogonal to both lattice vector a and b.\n"); - } - exit(EXIT_FAILURE); - } - } if (pSPARC->NPT_NP_ANGLES==1){ - if (pSPARC_Input->NPTscaleVecs[0] == 0 || pSPARC_Input->NPTscaleVecs[1] == 0 || pSPARC_Input->NPTscaleVecs[2] == 0 || pSPARC_Input->NPTconstraintFlag != 0 || pSPARC_Input->NPTspecialconstraint != 0){ + if (pSPARC_Input->NPTscaleVecs[0] == 0 || pSPARC_Input->NPTscaleVecs[1] == 0 || pSPARC_Input->NPTscaleVecs[2] == 0 || pSPARC_Input->NPTconstraintFlag != 0){ printf("Angle changing in NPT_NP ensemble is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints of any kind imposed on them.\n"); exit(EXIT_FAILURE); } @@ -3058,16 +3046,8 @@ void SPARC_copy_input(SPARC_OBJ *pSPARC, SPARC_INPUT_OBJ *pSPARC_Input) { exit(EXIT_FAILURE); } } - if (pSPARC->NPHspecialconstraint == 1){ - if (pSPARC->NPHscaleVecs[0] == 0 || pSPARC->NPHscaleVecs[1] == 0 || pSPARC->NPHscaleVecs[2] != 0) { // a or b cannot be rescaled or c is being rescaled - if (!rank) { - printf("\nNPH_SPECIAL_CONSTRAINT has conflict with NPH_SCALE_VECS! Remember lattice vector a and b needs to be rescaled, lattice vector c has to remain fixed. Also lattice vector 'c' must be orthogonal to both lattice vector a and b.\n"); - } - exit(EXIT_FAILURE); - } - } if (pSPARC->NPH_ANGLES==1){ - if (pSPARC_Input->NPHscaleVecs[0] == 0 || pSPARC_Input->NPHscaleVecs[1] == 0 || pSPARC_Input->NPHscaleVecs[2] == 0 || pSPARC_Input->NPHconstraintFlag != 0 || pSPARC_Input->NPHspecialconstraint != 0){ + if (pSPARC_Input->NPHscaleVecs[0] == 0 || pSPARC_Input->NPHscaleVecs[1] == 0 || pSPARC_Input->NPHscaleVecs[2] == 0 || pSPARC_Input->NPHconstraintFlag != 0){ printf("Angle changing in NPH ensemble is only possible when all 3 lattice vectors are allowed to expand/shrink, and simultaneously there are scale NO constraints of any kind imposed on them.\n"); exit(EXIT_FAILURE); } @@ -4000,7 +3980,6 @@ void write_output_init(SPARC_OBJ *pSPARC) { else if (pSPARC->NPTconstraintFlag == 3) fprintf(output_fp," 23\n"); else if (pSPARC->NPTconstraintFlag == 4) fprintf(output_fp," 123\n"); fprintf(output_fp,"NPT_NP_ANGLES: %d\n",pSPARC->NPT_NP_ANGLES); - fprintf(output_fp,"NPT_NP_SPECIAL_CONSTRAINT: %d\n",pSPARC->NPTspecialconstraint); fprintf(output_fp,"NPT_NP_QMASS: %.15g\n",pSPARC->NPT_NP_qmass); fprintf(output_fp,"NPT_NP_BMASS: %.15g\n",pSPARC->NPT_NP_bmass); fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->pressure_external+pSPARC->stress_external[0] @@ -4024,7 +4003,6 @@ void write_output_init(SPARC_OBJ *pSPARC) { else if (pSPARC->NPHconstraintFlag == 3) fprintf(output_fp," 23\n"); else if (pSPARC->NPHconstraintFlag == 4) fprintf(output_fp," 123\n"); fprintf(output_fp,"NPH_ANGLES: %d\n",pSPARC->NPH_ANGLES); - fprintf(output_fp,"NPH_SPECIAL_CONSTRAINT: %d\n",pSPARC->NPHspecialconstraint); fprintf(output_fp,"NPH_BMASS: %.15g\n",pSPARC->NPH_bmass); fprintf(output_fp,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->pressure_external+pSPARC->stress_external[0] ,pSPARC->pressure_external+pSPARC->stress_external[1] @@ -4462,7 +4440,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT, - MPI_INT, MPI_INT, MPI_INT, MPI_INT, /* int */ + MPI_INT, MPI_INT, /* int */ MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, /* double array */ @@ -4508,7 +4486,7 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, /* int */ + 1, 1, /* int */ 9, 3, L_QMASS, L_kpoint, L_kpoint, L_kpoint, 6, 6,/* double array */ 1, 1, 1, 1, 1, @@ -4621,8 +4599,6 @@ void SPARC_Input_MPI_create(MPI_Datatype *pSPARC_INPUT_MPI) { MPI_Get_address(&sparc_input_tmp.NPHconstraintFlag, addr + i++); MPI_Get_address(&sparc_input_tmp.NPT_NP_ANGLES, addr + i++); MPI_Get_address(&sparc_input_tmp.NPH_ANGLES, addr + i++); - MPI_Get_address(&sparc_input_tmp.NPTspecialconstraint, addr + i++); - MPI_Get_address(&sparc_input_tmp.NPHspecialconstraint, addr + i++); MPI_Get_address(&sparc_input_tmp.MAXIT_FOCK, addr + i++); MPI_Get_address(&sparc_input_tmp.ExxAcc, addr + i++); MPI_Get_address(&sparc_input_tmp.ExxMemBatch, addr + i++); diff --git a/src/md.c b/src/md.c index d8034123..ba4d41fa 100644 --- a/src/md.c +++ b/src/md.c @@ -254,10 +254,6 @@ void main_MD(SPARC_OBJ *pSPARC) { free(avgvel); free(maxvel); free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; - } if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ free(pSPARC->ion_vel_fractional); free(pSPARC->Pm_ion); @@ -462,6 +458,10 @@ void Initialize_MD(SPARC_OBJ *pSPARC) { pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + + //double temp_mat[9]; + //cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat, 3); + //cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, temp_mat, 3, 0.0, pSPARC->external_stress_lattice, 3); if(strcmpi(pSPARC->MDMeth,"NPH")==0){ @@ -1436,10 +1436,11 @@ void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant. -Also performs NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant. NPH in this scheme is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference for NPT_NP and NPH: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." +/** + *@brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant. +Also performs NPH MD simulation , wherein number of particles, pressure and enthalpy (or generalized enthalpy of Thurston in case of anisotropic external stress) are kept constant. +NPH in this scheme is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. +Reference for NPT_NP and NPH: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." .Hereafter referred to as the 'Hernandez paper'. The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. Additional Reference for NPH: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." Physical Review B 55.14 (1997): 8733. @@ -1468,8 +1469,8 @@ void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *m pSPARC->elecgs_Count++; } -/* -Computes transpose of a matrix and adds it to the original matrix +/** + *@brief function to compute transpose of a matrix and adds it to the original matrix */ void transpose_and_add(double *matrix1){ //performs matrix1 = matrix1 + transpose(matrix1) @@ -1486,11 +1487,10 @@ void transpose_and_add(double *matrix1){ matrix1[5] = matrix1[7] = s12; } - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix +/** + *@brief function to be called during 'restart' of NPT_NP and NPH to initialize the cell ingredients such as 'full_lattice' (lattice vectors scaled by LATVEC scale, or LatUVec scaled by cell), reciprocal lattice, metric tensor, reciprocal metic tensor, angle between cell lattice vectors, cell volume, etc +In essence similar to 'fetch_MD_cell_ingredients' below, but called during 'restart' of NPT_NP and NPH */ - void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -1540,27 +1540,6 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ //Reassign LatVec it old values for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = oldLatVec[i];} - - // printf("Volume cell %lf \n",pSPARC->volumeCell); - // printf("range_x %lf \n",pSPARC->range_x); - // printf("range_y %lf \n",pSPARC->range_y); - // printf("range_z %lf \n",pSPARC->range_z); - - // for (int i = 0; i < 9; i++){ - // printf("FUll lattice[%d] is %lf \n",i,pSPARC->full_lattice[i]); - // } - - // if (pSPARC->Flag_latvec_scale == 1){ - // for (int i = 0; i < 9; i++){ - // printf("LatVec[%d] is %lf \n",i,pSPARC->LatVec[i]); - // } - // } - // if (pSPARC->Flag_latvec_scale == 0){ - // for (int i = 0; i < 9; i++){ - // printf("LatUVec[%d] is %lf \n",i,pSPARC->LatUVec[i]); - // } - // } - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); @@ -1598,6 +1577,10 @@ void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ } +/** + *@brief function to initialize the cell ingredients for NPT_NP or NPH, and for updating the cell ingredients in each step. +To compute 'full_lattice' (lattice vectors 'LatVec' scaled by LATVEC SCALE or LatUVec scaled by cell), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix, angle between cell lattice vectors, velocity of cell lattice vectors, update volume of the cell etc +*/ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -1616,9 +1599,9 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); // Cosine of Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma + pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha (angle between b and c) + pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta (angle between a and c) + pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma (angle between a and b) pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; @@ -1755,7 +1738,9 @@ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ } } - +/** + *@brief function to compute the kinetic energy (and temperature) of the ionic particles in NPT_NP and NPH ensemble +*/ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -1776,8 +1761,10 @@ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); //Update Ionic temperature; } - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ +/** + *@brief function to compute the kinetic stress of the ionic particles in NPT_NP and NPH ensemble +*/ +void Calculate_Kinetic_stress(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -1805,7 +1792,10 @@ void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); } - +/** + *@brief function to compute the initial hamiltonian of the system in NPT_NP and NPH ensemble. +Only called once during the 1st step of MD. Not to be called after restart. +*/ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -1828,8 +1818,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// // Calculating kinetic energy of ions - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel_fractional, 1); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->metric_tensor, 3, 0.0, pSPARC->Pm_ion, 3); int count = 0; for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { @@ -1837,7 +1826,7 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ count = count + 3 * pSPARC->nAtomv[ityp]; } // Calculate kinetic energy and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity + Calculate_Kinetic_stress(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper pSPARC->KE_save = pSPARC->KE; @@ -1861,6 +1850,10 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + + //cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat, 3); + //cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, temp_mat, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper @@ -1905,12 +1898,13 @@ void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ } -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - +/** + *@brief function is the main function of NPT_NP and NPH ensemble. + It solves Equations 18a to 18g in the Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." .Hereafter referred to as the 'Hernandez paper'.: + -updates momentum and position of the ionic particles + -updates momentum and position of the thermostat + -update momentum and position of the barostat + -calculate Hamiltonian of the system */ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { int rank; @@ -1923,52 +1917,31 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min double internal_stress_cartesian[9]; //Initialize some useful constants - double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]={0}; int NPT_NPHspecialconstraint; + double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]={0}; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; - NPT_NPHspecialconstraint = pSPARC->NPTspecialconstraint; - + baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } else{ NPT_NPH_ANGLES = pSPARC->NPH_ANGLES; NPT_NPHconstraintFlag = pSPARC->NPHconstraintFlag; NPT_NPHscaleVecs[0] = pSPARC->NPHscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPHscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPHscaleVecs[2]; - NPT_NPHspecialconstraint = pSPARC->NPHspecialconstraint; - + baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper } + double baro_const3 = 1.0 / baro_const1; - if (pSPARC->MDCount == 1){ + if (pSPARC->MDCount == 1){ // Do some checks/setup //Initialize constraint stress to 0 for (int i = 0; i < 9; i++){ pSPARC->constraint_stress[i] = 0.0; } } - //#ifdef DEBUG - // printf("QMASS: %lf\n",pSPARC->NPT_NP_qmass); - // printf("SNOSE[0] %lf \n",pSPARC->SNOSE[0]); - // printf("SNOSE[1] %lf \n",pSPARC->SNOSE[1]); - // printf("SNOSE[2] %lf \n",pSPARC->SNOSE[2]); - // printf("KE %lf \n",pSPARC->KE); - // printf("Kbaro %lf \n",pSPARC->Kbaro); - // printf("Ubaro %lf \n",pSPARC->Ubaro); - // printf("InitHamil %lf \n",pSPARC->init_Hamil_NPT_NP); - - // if (rank == 0){ - // printf(":Pm_ion:\n"); - // for(int atm = 0; atm < pSPARC->n_atom; atm++){ - // printf("%18.10E %18.10E %18.10E\n", pSPARC->Pm_ion[3 * atm], pSPARC->Pm_ion[3 * atm + 1], pSPARC->Pm_ion[3 * atm + 2]); - // } - // } - // printf("Intial angles %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); - // exit(EXIT_FAILURE); - //#endif - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// double factor; // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) @@ -2016,13 +1989,13 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs, NPT_NPHspecialconstraint); + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); } } else { if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs, NPT_NPHspecialconstraint); + compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); } } @@ -2034,33 +2007,32 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min } //Now impose the constraints on it - if ( NPT_NPHspecialconstraint == 1 ){ + for (int i = 0; i < 3; i++){ // If any of the lattice vectors is constrained from being rescaled, set its momentum to 0 + if (NPT_NPHscaleVecs[i] == 0){ + pSPARC->Pm_metric_tensor[4 * i] = 0; //setting that corresponding diagonal element to 0 + } + } + + if ( (NPT_NPHscaleVecs[2]) == 0 && (fabs(pSPARC->initialLatVecAngles[0]) <= 1e-12) && (fabs(pSPARC->initialLatVecAngles[1]) <= 1e-12) ){ //Special constraint 1: a and b can vary, c must not vary. Further, the angle between c and a, or between c and b, must be 90 degrees. pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; pSPARC->Pm_metric_tensor[5] = 0; pSPARC->Pm_metric_tensor[2] = 0; } - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; + else if ( (NPT_NPHscaleVecs[1]) == 0 && (fabs(pSPARC->initialLatVecAngles[0]) <= 1e-12) && (fabs(pSPARC->initialLatVecAngles[2]) <= 1e-12) ){ //Special constraint 2: a and c can vary, b must not vary. Further, the angle between b and a, or between b and c, must be 90 degrees. pSPARC->Pm_metric_tensor[4] = 0; + pSPARC->Pm_metric_tensor[1] = 0; + pSPARC->Pm_metric_tensor[3] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[7] = 0; } - //Only |c| varies, |a| and |b| are fixed - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - - //Only |a| varies, |b| and |c| are fixed - else if (NPT_NPHscaleVecs[0] == 1 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 0){ - gpig[4] = 0; - gpig[8] = 0; - } - - //Only |b| varies, |a| and |c| are fixed - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 1 && NPT_NPHscaleVecs[2] == 0){ - gpig[0] = 0; - gpig[8] = 0; + else if ( (NPT_NPHscaleVecs[0]) == 0 && (fabs(pSPARC->initialLatVecAngles[1]) <= 1e-12) && (fabs(pSPARC->initialLatVecAngles[2]) <= 1e-12) ){ //Special constraint 1: b and c can vary, a must not vary. Further, the angle between a and b, or between a and c, must be 90 degrees. + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[1] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + pSPARC->Pm_metric_tensor[3] = 0; + pSPARC->Pm_metric_tensor[6] = 0; } @@ -2082,6 +2054,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); exit(EXIT_FAILURE); } + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->forces, 3, pSPARC->full_lattice, 3, 0.0, ion_forces_fractional, 3); // Eqn. 18i: momentum += 0.5 * dt * S * D2C cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); @@ -2094,24 +2067,30 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); count += 3 * pSPARC->nAtomv[ityp]; } - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + // Calculate kinetic stress + Calculate_Kinetic_stress(pSPARC); + // Calculate total internal pressure for (int i = 0; i < 9; i++){ - pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - pSPARC->internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); + pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - pSPARC->internal_stress_fractional[i] - pSPARC->constraint_stress[i] ) / pSPARC->volumeCell; } - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); //Update Hamiltonian double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ + + //TODO: The three lines below which are currently commented can be uncommented in case and checked in future. They are placed here if one wants to check forming the initial hamiltonian at t = 0, currently the initial hamiltonian is formed at t = -dt/2 + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; // } pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper } else { + + //TODO: The three lines below which are currently commented can be uncommented in case and checked in future. They are placed here if one wants to check forming the initial hamiltonian at t = 0, currently the initial hamiltonian is formed at t = -dt/2 + // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; // } @@ -2139,15 +2118,14 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min #endif // For printing, convert the total internal stress, constraint stress and the kinetic stress to cartesian coordinates - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); //Already divided by volume earlier - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->total_internal_stress, 3); //Mutliplied by 2 so as to remove the effect of previous divisions by 2 in the kinetic_stress, internal_stress_fractional + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); //Already divided by volume earlier + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->total_internal_stress, 3); //Mutliplied by 2 so as to remove the effect of previous divisions by 2 in the kinetic_stress, internal_stress_fractional - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->constraint_stress, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->constraint_stress, 3); - + cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->constraint_stress, 3, 0.0, temp_mat, 3); + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->constraint_stress, 3); // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// @@ -2218,49 +2196,42 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); count = count + 3 * pSPARC->nAtomv[ityp]; } - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); + // Calculate kinetic stress + Calculate_Kinetic_stress(pSPARC); - // Now we update/Step-up the momenta of the barostat by dt/2 // This setup corresponds to Eqn. 18b in the Hernandez paper // This needs to be solved iteratively Update_metric_tensor_momenta_iteratively_half_step(pSPARC); //Now impose the constraints on it - if ( NPT_NPHspecialconstraint == 1 ){ + for (int i = 0; i < 3; i++){ // If any of the lattice vectors is constrained from being rescaled, set its momentum to 0 + if (NPT_NPHscaleVecs[i] == 0){ + pSPARC->Pm_metric_tensor[4 * i] = 0; //setting that corresponding diagonal element to 0 + } + } + + if ( (NPT_NPHscaleVecs[2]) == 0 && (fabs(pSPARC->initialLatVecAngles[0]) <= 1e-12) && (fabs(pSPARC->initialLatVecAngles[1]) <= 1e-12) ){ //Special constraint 1: a and b can vary, c must not vary. Further, the angle between c and a, or between c and b, must be 90 degrees. pSPARC->Pm_metric_tensor[8] = 0; pSPARC->Pm_metric_tensor[7] = 0; pSPARC->Pm_metric_tensor[6] = 0; pSPARC->Pm_metric_tensor[5] = 0; pSPARC->Pm_metric_tensor[2] = 0; } - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; + else if ( (NPT_NPHscaleVecs[1]) == 0 && (fabs(pSPARC->initialLatVecAngles[0]) <= 1e-12) && (fabs(pSPARC->initialLatVecAngles[2]) <= 1e-12) ){ //Special constraint 2: a and c can vary, b must not vary. Further, the angle between b and a, or between b and c, must be 90 degrees. pSPARC->Pm_metric_tensor[4] = 0; + pSPARC->Pm_metric_tensor[1] = 0; + pSPARC->Pm_metric_tensor[3] = 0; + pSPARC->Pm_metric_tensor[5] = 0; + pSPARC->Pm_metric_tensor[7] = 0; } - //Only |c| varies, |a| and |b| are fixed - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - - //Only |a| varies, |b| and |c| are fixed - else if (NPT_NPHscaleVecs[0] == 1 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 0){ - gpig[4] = 0; - gpig[8] = 0; - } - - //Only |b| varies, |a| and |c| are fixed - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 1 && NPT_NPHscaleVecs[2] == 0){ - gpig[0] = 0; - gpig[8] = 0; + else if ( (NPT_NPHscaleVecs[0]) == 0 && (fabs(pSPARC->initialLatVecAngles[1]) <= 1e-12) && (fabs(pSPARC->initialLatVecAngles[2]) <= 1e-12) ){ //Special constraint 1: b and c can vary, a must not vary. Further, the angle between a and b, or between a and c, must be 90 degrees. + pSPARC->Pm_metric_tensor[0] = 0; + pSPARC->Pm_metric_tensor[1] = 0; + pSPARC->Pm_metric_tensor[2] = 0; + pSPARC->Pm_metric_tensor[3] = 0; + pSPARC->Pm_metric_tensor[6] = 0; } - // Now we update/Step-up the momenta of the thermostat by dt/2 @@ -2291,7 +2262,7 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min // This setup corresponds to Eqn. 18d in the Hernandez paper double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) + if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip if running NPH ensemble) while (1) { S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; if (fabs(S_temp - S_new) < 1e-7) { @@ -2337,18 +2308,20 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min fetch_MD_cell_ingredients(pSPARC, true); //Update Atomic position in fractional coordinates (Eqn. 18f in Hernandez paper) cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel_fractional, 1, atom_pos_fractional, 1); - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) + // Now reconvert atomic positions to cartesian coordinates cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, atom_pos_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->atom_pos, 3); free(atom_pos_fractional); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); - //Update atomic positions and restore ionic velocities - cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); + // Now reconvert velocity of ions to cartesian coordinates (this step is not actually needed, as these ionic velocities are not used anywhere in NPT_NP) + cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0 / S_new, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); //cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel_fractional, 1); //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); + //cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat, 3); + //cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, temp_mat, 3, 0.0, pSPARC->external_stress_lattice, 3); + pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential //Update kinetic energy and kinetic stress based on new S @@ -2368,8 +2341,13 @@ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *min // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// } -// IF and When this function is called, it imposes a universal constraint of all angles between lattice vectors being FIXED; on top of other constraints explicitly imposed in the function through 'if' condition -void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs, int *NPT_NPHspecialconstraint){ + +/** + *@brief function to impose constraints on the update of barostat momentum. To be called once per NPT_NP or NPH step. +If and When this function is called, it imposes a universal constraint of all angles between lattice vectors being FIXED; +This is on top of other constraints explicitly imposed in the function through 'if' condition +*/ +void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); //Initialize some useful constants @@ -2394,47 +2372,38 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper } - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (NPT_NPHconstraintFlag == 4){ + for (int i = 0; i < 3; i++){ // If any of the lattice vectors is constrained from being rescaled, set its momentum to 0 + if (NPT_NPHscaleVecs[i] == 0){ + gpig[4 * i] = 0; //setting that corresponding diagonal element to 0 + } + } + + if (NPT_NPHconstraintFlag == 4){ // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; gpig[4] = gpig[0]; gpig[8] = gpig[0]; } - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (NPT_NPHconstraintFlag == 1){ + else if (NPT_NPHconstraintFlag == 1){ // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED gpig[0] = (gpig[0] + gpig[4]) / 2; gpig[4] = gpig[0]; - if (NPT_NPHscaleVecs[2] == 0){ - gpig[8] = 0; - } } - // |a| = |c| and |b| can vary independently; and all angles between lattice vectors are FIXED - else if (NPT_NPHconstraintFlag == 2){ + else if (NPT_NPHconstraintFlag == 2){ // |a| = |c| and |b| can vary independently; and all angles between lattice vectors are FIXED gpig[0] = (gpig[0] + gpig[8]) / 2; gpig[8] = gpig[0]; - if (NPT_NPHscaleVecs[1] == 0){ - gpig[4] = 0; - } } - - // |b| = |c| and |a| can vary independently; and all angles between lattice vectors are FIXED - else if (NPT_NPHconstraintFlag == 3){ + + else if (NPT_NPHconstraintFlag == 3){ // |b| = |c| and |a| can vary independently; and all angles between lattice vectors are FIXED gpig[4] = (gpig[4] + gpig[8]) / 2; gpig[8] = gpig[4]; - if (NPT_NPHscaleVecs[0] == 0){ - gpig[0] = 0; - } } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if ( NPT_NPHspecialconstraint==1 ){ + + if ( (NPT_NPHscaleVecs[2]) == 0 && (fabs(pSPARC->initialLatVecAngles[0]) <= 1e-12) && (fabs(pSPARC->initialLatVecAngles[1]) <= 1e-12) ){ // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED, and further the lattice vector 'c' must be orthogonal to lattice vectors 'a' and 'b' gpig[8] = 0; gpig[7] = 0; gpig[6] = 0; @@ -2442,25 +2411,22 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int gpig[2] = 0; } - //Only |c| varies, |a| and |b| are fixed - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - gpig[0] = 0; + else if ( (NPT_NPHscaleVecs[1]) == 0 && (fabs(pSPARC->initialLatVecAngles[0]) <= 1e-12) && (fabs(pSPARC->initialLatVecAngles[2]) <= 1e-12) ){ // Only |a| and |c| varies, no changes in third direction i.e |b| is fixed; and all angles between lattice vectors are FIXED, and further the lattice vector 'b' must be orthogonal to lattice vectors 'a' and 'c' gpig[4] = 0; + gpig[1] = 0; + gpig[3] = 0; + gpig[5] = 0; + gpig[7] = 0; } - //Only |a| varies, |b| and |c| are fixed - else if (NPT_NPHscaleVecs[0] == 1 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 0){ - gpig[4] = 0; - gpig[8] = 0; - } - - //Only |b| varies, |a| and |c| are fixed - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 1 && NPT_NPHscaleVecs[2] == 0){ - gpig[0] = 0; - gpig[8] = 0; + else if ( (NPT_NPHscaleVecs[0]) == 0 && (fabs(pSPARC->initialLatVecAngles[1]) <= 1e-12) && (fabs(pSPARC->initialLatVecAngles[2]) <= 1e-12) ){ // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED, and further the lattice vector 'a' must be orthogonal to lattice vectors 'b' and 'c' + gpig[0] = 0; + gpig[1] = 0; + gpig[2] = 0; + gpig[3] = 0; + gpig[6] = 0; } - constraint_velocity[0] = gpig[0] * baro_const4; constraint_velocity[4] = gpig[4] * baro_const4; constraint_velocity[8] = gpig[8] * baro_const4; @@ -2486,7 +2452,11 @@ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int } } - +/** + *@brief function to update the Metric tensor components in NPT_NP and NPH ensemble iteratively in one single step (from time = t to t+dt). +This is Eqn. 18e in the Hernandez paper +To be called once per NPT_NP or NPH step. +*/ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_ANGLES, int NPT_NPHconstraintFlag){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -2619,7 +2589,11 @@ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, do } - +/** + *@brief function to update the momentum metric tensor (barostat variable) in NPT_NP and NPH ensemble iteratively in one half step (from time = t to t+dt/2). +This is Eqn. 18b in the Hernandez paper +To be called once per NPT_NP or NPH step. The other half update happens within the 'NPT_NP_and_NPH_main' subroutine +*/ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -2724,7 +2698,7 @@ void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; } -/** +/** * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c */ void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { @@ -2920,8 +2894,10 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); fprintf(output_md,":Desc_SNOSE[0]: Position variable of the thermostat\n"); fprintf(output_md,":Desc_SNOSE[1]: Velocity variable of the thermostat\n"); - } else + } else{ fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha \n"); + fprintf(output_md,":Desc_NPH_Enthalpy: Enthalpy of the NPH system (or generalized enthalpy in case of anisotropic stress). This quantity is same as NPH Hamiltonian (NPH_HAMIL) plus the initial NPH hamiltonian. Unit = Ha \n"); + } } if(pSPARC->Calc_stress == 1){ fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) @@ -2973,9 +2949,10 @@ void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *ma fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); fprintf(output_md,":SNOSE[0]:%18.10E \n", pSPARC->SNOSE[0]); fprintf(output_md,":SNOSE[1]:%18.10E \n", pSPARC->SNOSE[1]); - } if(strcmpi(pSPARC->MDMeth,"NPH") == 0) + } if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); - + fprintf(output_md,":NPH_ENTHALPY:%18.10E \n", pSPARC->Hamiltonian_NPH + pSPARC->init_Hamil_NPH); + } // Print atomic position if(pSPARC->PrintAtomPosFlag){ fprintf(output_md,":R:\n"); @@ -3879,4 +3856,4 @@ void RestartMD(SPARC_OBJ *pSPARC) { void Rename_restart(SPARC_OBJ *pSPARC) { if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} \ No newline at end of file +} diff --git a/src/readfiles.c b/src/readfiles.c index db0c853a..53bb4840 100644 --- a/src/readfiles.c +++ b/src/readfiles.c @@ -780,9 +780,6 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } else if (strcmpi(str,"NPT_NP_ANGLES:") == 0){ fscanf(input_fp,"%d",&pSPARC_Input->NPT_NP_ANGLES); fscanf(input_fp, "%*[^\n]\n"); - } else if (strcmpi(str,"NPT_NP_SPECIAL_CONSTRAINT:") == 0){ - fscanf(input_fp,"%d",&pSPARC_Input->NPTspecialconstraint); - fscanf(input_fp, "%*[^\n]\n"); } else if (strcmpi(str,"NPH_SCALE_VECS:") == 0) { int dir[3] = {0, 0, 0}; pSPARC_Input->NPHscaleVecs[0] = 0; pSPARC_Input->NPHscaleVecs[1] = 0; pSPARC_Input->NPHscaleVecs[2] = 0; @@ -825,9 +822,6 @@ void read_input(SPARC_INPUT_OBJ *pSPARC_Input, SPARC_OBJ *pSPARC) { } else if (strcmpi(str,"NPH_ANGLES:") == 0){ fscanf(input_fp,"%d",&pSPARC_Input->NPH_ANGLES); fscanf(input_fp, "%*[^\n]\n"); - } else if (strcmpi(str,"NPH_SPECIAL_CONSTRAINT:") == 0){ - fscanf(input_fp,"%d",&pSPARC_Input->NPHspecialconstraint); - fscanf(input_fp, "%*[^\n]\n"); } else if (strcmpi(str,"NPT_NH_QMASS:") == 0) { fscanf(input_fp,"%d",&pSPARC_Input->NPT_NHnnos); for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC_Input->NPT_NHnnos; subscript_NPTNH_qmass++){ From 74bd2b7e9fd0ae3fe0d91a40a9eb43773660f717 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:11:58 -0400 Subject: [PATCH 66/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- src/include/isddft.h | 7 ------- src/include/md.h | 44 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/include/isddft.h b/src/include/isddft.h index b14abbb0..5e2fa28f 100644 --- a/src/include/isddft.h +++ b/src/include/isddft.h @@ -869,12 +869,9 @@ typedef struct _SPARC_OBJ{ int NPTconstraintFlag; // confinement on side length of cell. none: no length confinement (default); 1: a:b keeps unchanged; 2: a:c keeps unchanged; // 3: b:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. int NPT_NP_ANGLES; // Flag to decide whether changing of angles during NPT_NP ensemble is allowed - int NPTspecialconstraint; // these are special constraint. 1: Used for graphene which allows only 2D flexibility along a and b which forms 120 degree angles between them (no change along c direction, which forms 90 degree angles with a and with b). - // Currently only 1 special constraint is supported, others will be supported in future int NPHscaleVecs[3]; // Same as NPTscaleVecs, but meant for NPH int NPHconstraintFlag; // Same as NPTconstraintFlag, but meant for NPH int NPH_ANGLES; // Same as NPT_NP_ANGLES, but meant for NPH - int NPHspecialconstraint; // Same as NPTspecialconstraint, but meant for NPH int NPTisotropicFlag; // whether it is an isotropic cell expansion; a:b:c keeps similar during NPT. // For NPT_NH, if all 3 lattive vectors are scalable, it will be an isotropic expansion; @@ -1465,15 +1462,11 @@ typedef struct _SPARC_INPUT_OBJ{ // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPT_NP. int NPT_NP_ANGLES; // whether to allow for changing angles in NPT_NP, it can only be allowed (by setting to 1), when all lattice vectors can be rescaled using NPTscaleVecs: 1 2 3; // and when there are NO constraints in length confinement (so no input in NPTconstraintFlag) - int NPTspecialconstraint; // these are special constraint. 1: Used for graphene which allows only 2D flexibility along a and b which forms 120 degree angles between them (no change along c direction, which forms 90 degree angles with a and with b). - // Currently only 1 special constraint is supported, others will be supported in future int NPHscaleVecs[3]; // which lattice vector can be rescaled in NPH? int NPHconstraintFlag; // confinement on side length of cell. none: no length confinement (default); 1: a:b keeps unchanged; 2: a:c keeps unchanged; // 3: a:c keeps unchanged; 4: a:b:c keeps unchanged, isotropic expansion. It is only available for NPH. int NPH_ANGLES; // whether to allow for changing angles in NPH, it can only be allowed (by setting to 1), when all lattice vectors can be rescaled using NPHscaleVecs: 1 2 3; // and when there are NO constraints in length confinement (so no input in NPHconstraintFlag) - int NPHspecialconstraint; - double pressure_external; // Externally applied hydrostatic pressure of NPT_NP or NPH system, UNIT on input file is GPa double stress_external[6]; // Externally applied anisotropic stress tensor (applied separately from pressure_external) for NPT_NP or NPH system, UNIT on input file is GPa //In NPT_NP and NPH, the target_stress[i] = pr_external+stress_external[i]; in contrast to NPT_NH where there is just target_pressure. diff --git a/src/include/md.h b/src/include/md.h index f244e53f..ff94b52a 100644 --- a/src/include/md.h +++ b/src/include/md.h @@ -153,33 +153,61 @@ void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC); void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC); /* -@ brief: Performs Molecular Dynamics using NPT_NP. +@ brief: Performs Molecular Dynamics using NPT_NP or NPH. */ - void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis); +/* +@ brief: Do one full step of 'NPT_NP' or 'NPH' ensemble i.e. Solve equation 18a to 18g of the Hernandez paper and calculate the Hamiltonian of the same system. +*/ void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis); + +/* +@ brief: function to calculate the initial hamiltonian in 'NPT_NP' or 'NPH'. +*/ +void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC); + /* -@ brief: Calculates cell angles, reciprocal lattice vectors, metric and reciprocal metric tensors, for use in NPT_NP and NPH dynamics +@ brief: Initializes cell ingredients during the start of 'NPT_NP' or 'NPH', or updates the cell after each step. + Cell ingredients include but not limited to: cell angles, reciprocal lattice vectors, metric tensor and reciprocal metric tensors, for use in NPT_NP and NPH dynamics */ void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell); -void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC); -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC); +/* +@ brief: Initializes cell ingredients during the restart of 'NPT_NP' or 'NPH'. To be called only once in the first step after restart. +*/ +void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC); +/* +@ brief: function to transpose a matrix and add to itself +*/ void transpose_and_add(double *matrix1); +/* +@ brief: function to compute the kinetic energy of the ionic particles in 'NPT_NP' or 'NPH' +*/ void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC); -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC); - -void Calculate_Kinetic_energy_and_Kinetic_stress(SPARC_OBJ *pSPARC); +/* +@ brief: function to compute the kinetic stress of the ionic particles in 'NPT_NP' or 'NPH' +*/ +void Calculate_Kinetic_stress(SPARC_OBJ *pSPARC); +/* +@brief: function to impose constraints on the flexibility of the cell in the 'NPT_NP' or 'NPH' +*/ void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs); +/* +@brief: function to update the components of the metric tensor in one full step iteratively in 'NPT_NP' or 'NPH'. +*/ void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_ANGLES, int NPT_NPHconstraintFlag); +/* +@brief: function to update the momentum of the metric tensor in one half step iteratively in 'NPT_NP' or 'NPH'. +*/ void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC); + /** * @ brief: function to convert non cartesian to cartesian coordinates and velocities, from initialization.c */ From 46d08dc32a6b319480f648c804f5f089b4107152 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:12:56 -0400 Subject: [PATCH 67/87] Delete src/MD_copy1.c --- src/MD_copy1.c | 3861 ------------------------------------------------ 1 file changed, 3861 deletions(-) delete mode 100644 src/MD_copy1.c diff --git a/src/MD_copy1.c b/src/MD_copy1.c deleted file mode 100644 index 0d7c63c8..00000000 --- a/src/MD_copy1.c +++ /dev/null @@ -1,3861 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include -#include -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - pSPARC->t_md = MPI_Wtime(); - - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - - if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // For NPT_NP and NPH, a similar but slightly modified printing scheme is run, as the printing instances in this below setup is not compatible with NPT_NP and NPH ensemble, i.e. the printing setup in the below scheme (if condition) if used for NPT_NP and NPH would be corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies. So the quantities are not in-sync when being printed to 'log' or 'aimd' file, so this setup is done separately for NPT_NP and NPH with printing happening when all quantities are in-sync and belong to same time = t - FILE *output_md, *output_fp; - // File output_md stores all the desirable properties from a MD run - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); - #ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); - #endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,":MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); - #ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); - #endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - - } else { // Carry out the above procedure in slightly modified printing manner for NPT_NP and NPH ensemble - // File output_md stores all the desirable properties from a MD run - FILE *output_md; - - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - // if(pSPARC->RestartFlag == 0){ - // fprintf(output_md,":MDSTEP: %d\n", 1); - // fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - // MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - // Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - // } - - fclose(output_md); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount; // Count is the MD step no. to be performed - #ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); - #endif - - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); - - NPT_NP_and_NPH(pSPARC, avgvel, maxvel, mindis); - - // This is true, restart happens from the instance when position are at time = t, whereas momenta are lagging behind by dt/2, so they belong to time = t-dt/2 (unlike printing all quantities to an MD file, which happens when all quantities belong to time = t, and in-sync with each other) - if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - - } - - - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ - free(pSPARC->ion_vel_fractional); - free(pSPARC->Pm_ion); - } -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - } - else{ - pSPARC->initialLatVecLength[0] = 1; pSPARC->initialLatVecLength[1] = 1; pSPARC->initialLatVecLength[2] = 1; - } - - pSPARC->maxTimeIter = 100; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - if(pSPARC->NPH_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - } - - fetch_MD_cell_ingredients(pSPARC, false); - pSPARC->pressure_external /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble\n"); - } - } - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); - exit(EXIT_FAILURE); - } - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); - exit(EXIT_FAILURE); - } - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->maxTimeIter = 100; - - //fetch_MD_cell_ingredients_restart(pSPARC); - pSPARC->KE_save = 0.0; - - pSPARC->pressure_external /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= CONST_HA_BOHR3_GPA; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - - - if(strcmpi(pSPARC->MDMeth,"NPH")==0){ - pSPARC->NPT_NP_qmass = 0; - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - } - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - - //Calculate_ionic_stress(pSPARC); - - //Pm_ion memory allocation already done within 'RestartMD' function as that is being MPI communicated - pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic fractional velocity array.\n"); - exit(EXIT_FAILURE); - } - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; - for (int i = 0; i < 9; i++){ - pSPARC->mean_total_internal_stress[i] = 0.0; - pSPARC->std_total_internal_stress[i] = 0.0; - } - -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant. -Also performs NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant. NPH in this scheme is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference for NPT_NP and NPH: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Additional Reference for NPH: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)){ - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - //NPT_NPH_main routine - NPT_NPH_main(pSPARC, avgvel, maxvel, mindis); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; -} - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ - -void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double oldLatVec[9]; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - if (pSPARC->Flag_latvec_scale == 0){ - for (int i = 0; i < 3; i++) { - pSPARC->full_lattice[i] = pSPARC->LatUVec[i] * pSPARC->range_x; - pSPARC->full_lattice[i+3] = pSPARC->LatUVec[i + 3] * pSPARC->range_y; - pSPARC->full_lattice[i+6] = pSPARC->LatUVec[i + 6] * pSPARC->range_z; - } - } - else{ - for (int i = 0; i < 3; i++) { - pSPARC->full_lattice[i] = pSPARC->LatVec[i] * pSPARC->latvec_scale_x; - pSPARC->full_lattice[i+3] = pSPARC->LatVec[i+3] * pSPARC->latvec_scale_y; - pSPARC->full_lattice[i+6] = pSPARC->LatVec[i+6] * pSPARC->latvec_scale_z; - } - - } - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - if (pSPARC->Flag_latvec_scale == 1){ // for Flag_latvec_scale == 0, the update for 'range_x,y,z' has already happened within restart function - pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); - pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); - pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - } - else{ - pSPARC->initialLatVecLength[0] = 1; pSPARC->initialLatVecLength[1] = 1; pSPARC->initialLatVecLength[2] = 1; - } - - //Assign full_lattice to LatVec for updating various quantities in 'Cart2nonCart_transformMat' - for (int i = 0; i < 9; i++){oldLatVec[i] = pSPARC->LatVec[i];} - for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = pSPARC->full_lattice[i];} - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT (this function updates all quantites based on 'LatVec' variable as input, but we actually want it based on 'full_lattice' variable, which contains all the cell lattice vectors updates, so we do the step above this to assign full_lattice to LatVec) - Cart2nonCart_transformMat(pSPARC); - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - //Reassign LatVec it old values - for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = oldLatVec[i];} - - - // printf("Volume cell %lf \n",pSPARC->volumeCell); - // printf("range_x %lf \n",pSPARC->range_x); - // printf("range_y %lf \n",pSPARC->range_y); - // printf("range_z %lf \n",pSPARC->range_z); - - // for (int i = 0; i < 9; i++){ - // printf("FUll lattice[%d] is %lf \n",i,pSPARC->full_lattice[i]); - // } - - // if (pSPARC->Flag_latvec_scale == 1){ - // for (int i = 0; i < 9; i++){ - // printf("LatVec[%d] is %lf \n",i,pSPARC->LatVec[i]); - // } - // } - // if (pSPARC->Flag_latvec_scale == 0){ - // for (int i = 0; i < 9; i++){ - // printf("LatUVec[%d] is %lf \n",i,pSPARC->LatUVec[i]); - // } - // } - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - -} - -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - - for (int i = 0; i < 3; i++) { - pSPARC->full_lattice[i] = pSPARC->LatUVec[i] * pSPARC->range_x; - pSPARC->full_lattice[i+3] = pSPARC->LatUVec[i + 3] * pSPARC->range_y; - pSPARC->full_lattice[i+6] = pSPARC->LatUVec[i + 6] * pSPARC->range_z; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Cosine of Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - - pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; - pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; - pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; - - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); - - if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); - pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); - pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - - //Assign full_lattice to LatVec for updating various quantities in 'Cart2nonCart_transformMat' - double oldLatVec[9]; - for (int i = 0; i < 9; i++){oldLatVec[i] = pSPARC->LatVec[i];} - for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = pSPARC->full_lattice[i];} - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT (this function updates all quantites based on 'LatVec' variable as input, but we actually want it based on 'full_lattice' variable, which contains all the cell lattice vectors updates, so we do the step above this to assign full_lattice to LatVec) - Cart2nonCart_transformMat(pSPARC); - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - //Reassign LatVec it old values - for (int i = 0; i < 9; i++){pSPARC->LatVec[i] = oldLatVec[i];} - - // Update/Calculate new angles between lattice vectors - pSPARC->angle_12 = acos( pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y) ) * 180 / M_PI; - pSPARC->angle_13 = acos( pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z) ) * 180 / M_PI; - pSPARC->angle_23 = acos( pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z) ) * 180 / M_PI; - - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - - } - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell@Rotation_matrix.T = old_cell; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate the velocity of cell lattice vectors (only useful in 1st MD step (if starting with nonzero lattice vector velocities: but as of now this step is not really useful, as we are by default only supporting zero initializing for lattice vector velocities)) - else { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - else { - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - } - - temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double vector[3]={0.0}; - pSPARC->KE = 0.0; - - int count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, &pSPARC->Pm_ion[count*3], 1, 0.0, vector, 1); - pSPARC->KE += cblas_ddot(3, vector, 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - count++; - } - } - - pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); -} - - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+2] * pSPARC->ion_vel_fractional[count*3+2]; - count++; - } - } - - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else { - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - - // Calculating kinetic energy of ions - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel_fractional, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->metric_tensor, 3, 0.0, pSPARC->Pm_ion, 3); - int count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - cblas_dscal(3 * pSPARC->nAtomv[ityp], pSPARC->Mass[ityp], &pSPARC->Pm_ion[count], 1); - count = count + 3 * pSPARC->nAtomv[ityp]; - } - // Calculate kinetic energy and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - pSPARC->KE_save = pSPARC->KE; - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3 * baro_const2, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - - double sumAllHamilTerms; - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - - #ifdef DEBUG - if (rank == 0) { - printf("within init"); - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - } - } - #endif - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// - - //Initialize constraint stress to 0 - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; - } -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp = pSPARC->kB * pSPARC->thermos_T; - int count; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; - - //Initialize some useful constants - double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]={0}; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; - NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; - NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; - - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else{ - NPT_NPH_ANGLES = pSPARC->NPH_ANGLES; - NPT_NPHconstraintFlag = pSPARC->NPHconstraintFlag; - NPT_NPHscaleVecs[0] = pSPARC->NPHscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPHscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPHscaleVecs[2]; - - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const3 = 1.0 / baro_const1; - - if (pSPARC->MDCount == 1){ - //Initialize constraint stress to 0 - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; - } - } - - //#ifdef DEBUG - // printf("QMASS: %lf\n",pSPARC->NPT_NP_qmass); - // printf("SNOSE[0] %lf \n",pSPARC->SNOSE[0]); - // printf("SNOSE[1] %lf \n",pSPARC->SNOSE[1]); - // printf("SNOSE[2] %lf \n",pSPARC->SNOSE[2]); - // printf("KE %lf \n",pSPARC->KE); - // printf("Kbaro %lf \n",pSPARC->Kbaro); - // printf("Ubaro %lf \n",pSPARC->Ubaro); - // printf("InitHamil %lf \n",pSPARC->init_Hamil_NPT_NP); - - // if (rank == 0){ - // printf(":Pm_ion:\n"); - // for(int atm = 0; atm < pSPARC->n_atom; atm++){ - // printf("%18.10E %18.10E %18.10E\n", pSPARC->Pm_ion[3 * atm], pSPARC->Pm_ion[3 * atm + 1], pSPARC->Pm_ion[3 * atm + 2]); - // } - // } - // printf("Intial angles %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); - // exit(EXIT_FAILURE); - //#endif - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double factor; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof * ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; - pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; - #ifdef DEBUG - if (rank == 0) { - printf("factor Eqn.18G is %12.9f\n", factor); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - } - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat_b, 3); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, pSPARC->reciprocal_lattice, 3, temp_mat_b, 3, 0.0, pSPARC->internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = (pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); - } - - } - else { - if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); - } - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i < 9; i++){ - temp_mat[i] = pSPARC->internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - double *ion_forces_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (ion_forces_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); - exit(EXIT_FAILURE); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->forces, 3, pSPARC->full_lattice, 3, 0.0, ion_forces_fractional, 3); - // Eqn. 18i: momentum += 0.5 * dt * S * D2C - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); - count += 3 * pSPARC->nAtomv[ityp]; - } - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); - - for (int i = 0; i < 9; i++){ - pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - pSPARC->internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); - - //Update Hamiltonian - double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; - // } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; - // } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - } - } - #endif - - // For printing, convert the total internal stress, constraint stress and the kinetic stress to cartesian coordinates - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); //Already divided by volume earlier - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->total_internal_stress, 3); //Mutliplied by 2 so as to remove the effect of previous divisions by 2 in the kinetic_stress, internal_stress_fractional - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->constraint_stress, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->constraint_stress, 3); - - - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - // ------------------------------------- BEGIN: PRINTING FOR NPT_NP OR NPH ENSEMBLE (this marks the end of one timestep) --------------------------------------// - - // Obtain updated velocities in cartesian coordinates for use in MD_QOI function - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); - - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount); - #endif - int Count = pSPARC->MDCount + pSPARC->restartCount; - int check1 = (pSPARC->PrintMDout == 1 && !rank); - - FILE *output_md; - FILE *output_fp; - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - if(check1) { - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,"\n\n"); - fprintf(output_md,":MDSTEP: %d\n", Count); - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - pSPARC->t_md); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - fclose(output_md); - } - - #ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - pSPARC->t_md)); - #endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - pSPARC->t_md)); - fclose(output_fp); - } - - // (this marks the start of MDCount^{th} step ), but do not move pSPARC->MDCount increment here, it is affecting other functions - pSPARC->t_md = MPI_Wtime(); - #ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount); - #endif - - // ------------------------------------- END: PRINTING FOR NPT_NP OR NPH ENSEMBLE (this marks the beginning of new timestep) --------------------------------------// - - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); - free(ion_forces_fractional); - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); - count = count + 3 * pSPARC->nAtomv[ityp]; - } - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); - - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC); - - //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - } - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp - S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - if (rank == 0){ - printf("%15.7f \n", S_new); - printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - - pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - - //Eqn. 18e is implicitly solved in the below subroutine - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new, NPT_NPH_ANGLES, NPT_NPHconstraintFlag); - - //Before updating cell parameters, convert cartesian atomic position coordinates to fractional - double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, pSPARC->reciprocal_lattice, 3, 0.0, atom_pos_fractional, 3); - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - //Update Atomic position in fractional coordinates (Eqn. 18f in Hernandez paper) - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel_fractional, 1, atom_pos_fractional, 1); - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, atom_pos_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->atom_pos, 3); - free(atom_pos_fractional); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); - //Update atomic positions and restore ionic velocities - cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); - //cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel_fractional, 1); - - - //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); - } - - // Update SNOSE[0] to S_new - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_new; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// -} - - -void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - else{ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (NPT_NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (NPT_NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (NPT_NPHscaleVecs[2] == 0 ){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_ANGLES, int NPT_NPHconstraintFlag){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - } - else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); - } - - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++){ - if (rank == 0){ - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - } - } - - if (NPT_NPH_ANGLES == 0){ - if (NPT_NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (NPT_NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; i < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } - - #ifdef DEBUG - if (rank == 0) { - for (int i = 0; i < 9; i++){ - printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); - } - } - #endif - -} - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-12; // tolerance criterion for checking convergence - double baro_const0, baro_const3; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - - } - else{ - baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - - } - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++){ - if (rank == 0){ - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); - #endif - } -} - - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - - - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha \n"); - } - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); - fprintf(output_md,":Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 \n"); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = 1 \n",pSPARC->MDMeth); - } else { - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); - fprintf(output_md,":Desc_SNOSE[0]: Position variable of the thermostat\n"); - fprintf(output_md,":Desc_SNOSE[1]: Velocity variable of the thermostat\n"); - } else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated as: kinetic_stress (positive convention) - electronic stress - constraint stress; as per (E. Hernandez, 2001) paper - } - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa \n"); - fprintf(output_md,":Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa \n"); - } - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); - fprintf(output_md,":SNOSE[0]:%18.10E \n", pSPARC->SNOSE[0]); - fprintf(output_md,":SNOSE[1]:%18.10E \n", pSPARC->SNOSE[1]); - } if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(output_md,":ANGLES:\n"); - fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(output_md,":VOLUME: %18.10E\n", pSPARC->volumeCell); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL:\n"); - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: \n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x / pSPARC->initialLatVecLength[0], pSPARC->range_y / pSPARC->initialLatVecLength[1], pSPARC->range_z / pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - else{ //Trigger NPT_NP or NPH ensemble stress printing - fprintf(output_md,":STRIO:\n"); //Ion-kinetic stress - double temp_stress[6]; - temp_stress[0] = pSPARC->kinetic_stress[0]; temp_stress[1] = pSPARC->kinetic_stress[1]; temp_stress[2] = pSPARC->kinetic_stress[2]; - temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[8]; - PrintStress (pSPARC, temp_stress, output_md); //Print kinetic stress as defined in the (E. Hernandez, 2001) paper - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i]; // stress_i or ionic stress function is never called in NPT_NP or NPH ensemble, so pSPARC->stress does not include contribution from it, and thus no need to subtract stress_i from pSPARC->stress, as done in other ensembles - PrintStress (pSPARC, stress_e, output_md); - fprintf(output_md,":CONSTRESS:\n"); //Constraint stress - temp_stress[0] = pSPARC->constraint_stress[0]; temp_stress[1] = pSPARC->constraint_stress[1]; temp_stress[2] = pSPARC->constraint_stress[2]; - temp_stress[3] = pSPARC->constraint_stress[4]; temp_stress[4] = pSPARC->constraint_stress[5]; temp_stress[5] = pSPARC->constraint_stress[8]; - PrintStress (pSPARC, temp_stress, output_md); - fprintf(output_md,":TOTSTRESS:\n"); //Print total internal stress accouting for the constraints in NPT_NP or NPH ensemble - temp_stress[0] = pSPARC->total_internal_stress[0]; temp_stress[1] = pSPARC->total_internal_stress[1]; temp_stress[2] = pSPARC->total_internal_stress[2]; - temp_stress[3] = pSPARC->total_internal_stress[4]; temp_stress[4] = pSPARC->total_internal_stress[5]; temp_stress[5] = pSPARC->total_internal_stress[8]; - PrintStress (pSPARC, temp_stress, output_md); - } - } - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i * CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i) * CONST_HA_BOHR3_GPA); - } - else{ //Trigger NPT_NP or NPH ensemble stress printing - double ion_kinetic_pressure, constraint_pressure; - ion_kinetic_pressure = 1.0 / 3.0 * (pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[4] + pSPARC->kinetic_stress[8]); //Kinetic stress is already multiplied by 2 - constraint_pressure = 1.0 / 3.0 * (pSPARC->constraint_stress[0] + pSPARC->constraint_stress[4] + pSPARC->constraint_stress[8]); //Constraint stress is already multiplied by 2 - fprintf(output_md,":PRESIO: %18.10E\n", ion_kinetic_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->internal_pressure - ion_kinetic_pressure + constraint_pressure) * CONST_HA_BOHR3_GPA); - fprintf(output_md,":CONPRES: %18.10E\n", constraint_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":TOTPRES: %18.10E\n", pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); //Also accounts for pressure due to constraint stress - } - - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig * CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":PREST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":MEAN_TOTSTRESS:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->mean_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[2] * CONST_HA_BOHR3_GPA - , pSPARC->mean_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[5] * CONST_HA_BOHR3_GPA - , pSPARC->mean_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[8] * CONST_HA_BOHR3_GPA); - fprintf(output_md,":STD_TOTSTRESS:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->std_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[2] * CONST_HA_BOHR3_GPA - , pSPARC->std_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[5] * CONST_HA_BOHR3_GPA - , pSPARC->std_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[8] * CONST_HA_BOHR3_GPA); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the quantities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE / pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - - // Compute Ionic stress/pressure - if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - } - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old, mean_total_internal_stress_old[9]; - int Count; - if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ - Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; - } - else{ - Count = pSPARC->MDCount + pSPARC->restartCount; - } - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - mean_internal_pressure_old = pSPARC->mean_internal_pressure; - for (int i = 0; i < 9; i++){mean_total_internal_stress_old[i] = pSPARC->mean_total_internal_stress[i];} - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; - for (int i = 0; i < 9; i++){pSPARC->mean_total_internal_stress[i] = (mean_total_internal_stress_old[i] * (Count - 1) + pSPARC->total_internal_stress[i]) / Count;} - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_internal_pressure = sqrt(fabs( ((pow(pSPARC->std_internal_pressure,2.0) + pow(mean_internal_pressure_old,2.0)) * (Count - 1) + pow(pSPARC->internal_pressure,2.0))/Count - pow(pSPARC->mean_internal_pressure,2.0) )); - for (int i = 0; i < 9; i++){pSPARC->std_total_internal_stress[i] = sqrt(fabs( ((pow(pSPARC->std_total_internal_stress[i],2.0) + pow(mean_total_internal_stress_old[i],2.0)) * (Count - 1) + pow(pSPARC->total_internal_stress[i],2.0))/Count - pow(pSPARC->mean_total_internal_stress[i],2.0) ));} - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(9, sizeof(double)); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - printf("\n"); - printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - fprintf(mdout,":Pm_ion:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->Pm_ion[3 * atm], pSPARC->Pm_ion[3 * atm + 1], pSPARC->Pm_ion[3 * atm + 2]); - } - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP or NPH ensemble - if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":NPT_NP_SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep - fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep - fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPH_bmass); - fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); - } - fprintf(mdout,":KE: %.15g\n",pSPARC->KE); - fprintf(mdout,":Kbaro: %.15g\n",pSPARC->Kbaro); - fprintf(mdout,":Ubaro: %.15g\n",pSPARC->Ubaro); - fprintf(mdout,":kinetic_stress: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->kinetic_stress[0], pSPARC->kinetic_stress[1], pSPARC->kinetic_stress[2] - , pSPARC->kinetic_stress[3], pSPARC->kinetic_stress[4], pSPARC->kinetic_stress[5] - , pSPARC->kinetic_stress[6], pSPARC->kinetic_stress[7], pSPARC->kinetic_stress[8]); - fprintf(mdout,":Pm_metric_tensor: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); - fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] - , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] - , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] - , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] - , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); - } - fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI ); - fprintf(mdout,":ROTATION_MATRIX: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] - , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] - , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":EXTERNAL_PRESSURE: %.15g\n", pSPARC->pressure_external * CONST_HA_BOHR3_GPA); - fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * CONST_HA_BOHR3_GPA - ,pSPARC->stress_external[1] * CONST_HA_BOHR3_GPA - ,pSPARC->stress_external[2] * CONST_HA_BOHR3_GPA - ,pSPARC->stress_external[3] * CONST_HA_BOHR3_GPA - ,pSPARC->stress_external[4] * CONST_HA_BOHR3_GPA - ,pSPARC->stress_external[5] * CONST_HA_BOHR3_GPA); - } - // Print temperature - fprintf(mdout,":TEL(K): %18.10E\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %18.10E\n", pSPARC->ion_T); - fprintf(mdout,":TELST(K): %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(mdout,":TIOST(K): %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(mdout,":PREST(Gpa): %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); - fprintf(mdout,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(mdout,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(mdout,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(mdout,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(mdout,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - printf("\nCannot allocate memory for ion momentum array!\n"); - exit(EXIT_FAILURE); - } - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 20)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 56 + 32)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 52 + 32)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 22) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - } - } else if (strcmpi(str,":V(Bohr/atu):") == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - } - } else if (strcmpi(str,":Pm_ion:") == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->Pm_ion[3 * atm], &pSPARC->Pm_ion[3 * atm + 1], &pSPARC->Pm_ion[3 * atm + 2]); - } - } - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TELST(K):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_elec_T); fscanf(rst_fp,"%lf", &pSPARC->std_elec_T); - }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); - }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); - pSPARC->mean_internal_pressure /= CONST_HA_BOHR3_GPA; pSPARC->std_internal_pressure /= CONST_HA_BOHR3_GPA; - }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); - }else if (strcmpi(str,":KENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_KE); fscanf(rst_fp,"%lf", &pSPARC->std_KE); - }else if (strcmpi(str,":FENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_PE); fscanf(rst_fp,"%lf", &pSPARC->std_PE); - }else if (strcmpi(str,":UENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_U); fscanf(rst_fp,"%lf", &pSPARC->std_U); - }else if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_Entropy); fscanf(rst_fp,"%lf", &pSPARC->std_Entropy); - } - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_TE_ext); fscanf(rst_fp,"%lf", &pSPARC->std_TE_ext); - } - } - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[0]); - else if (strcmpi(str,":NPT_NP_SNOSE[1]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[1]); - else if (strcmpi(str,":NPT_NP_SNOSE[2]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[2]); - else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); - } - if (strcmpi(str,":KE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->KE); - else if (strcmpi(str,":Kbaro:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->Kbaro); - else if (strcmpi(str,":Ubaro:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->Ubaro); - else if (strcmpi(str,":kinetic_stress:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[0]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[1]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[2]); - fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[3]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[4]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[5]); - fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[6]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[7]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[8]); - } else if (strcmpi(str,":Pm_metric_tensor:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[0]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[1]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[2]); - fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[3]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[4]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[5]); - fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[6]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[7]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[8]); - } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); - for (int i = 0; i < 3; i++){pSPARC->initialLatVecAngles[i] = cos(M_PI / 180 * pSPARC->initialLatVecAngles[i]);} - } else if (strcmpi(str,":CELL:") == 0) { - fscanf(rst_fp,"%lf", &pSPARC->range_x); fscanf(rst_fp,"%lf", &pSPARC->range_y); fscanf(rst_fp,"%lf", &pSPARC->range_z); - } else if (strcmpi(str,":LatUVec:") == 0) { - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); - } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); - - fscanf(rst_fp, "%*[^\n]\n"); - } else if (strcmpi(str,":LatVec:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); - fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); - fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); - } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[6]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[7]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[8]); - } else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":EXTERNAL_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->pressure_external); - else if (strcmpi(str,":EXTERNAL_STRESS:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->stress_external[0]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[1]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[2]); - fscanf(rst_fp,"%lf", &pSPARC->stress_external[3]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[4]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[5]); - } - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - MPI_Pack(pSPARC->Pm_ion, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->mean_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(pSPARC->SNOSE, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - MPI_Pack(&pSPARC->KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->Kbaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->Ubaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->kinetic_stress, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if (pSPARC->Flag_latvec_scale == 0){ - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if (pSPARC->Flag_latvec_scale == 1){ - MPI_Pack(&pSPARC->latvec_scale_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->latvec_scale_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->latvec_scale_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - MPI_Unpack(buff, l_buff, &position, pSPARC->Pm_ion, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - } - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, pSPARC->SNOSE, 3, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - MPI_Unpack(buff, l_buff, &position, &pSPARC->KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->Kbaro, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->Ubaro, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->kinetic_stress, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, MPI_COMM_WORLD); - if (pSPARC->Flag_latvec_scale == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->LatUVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if (pSPARC->Flag_latvec_scale == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->LatVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); - } - MPI_Unpack(buff, l_buff, &position, pSPARC->rotation_matrix, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->pressure_external, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->stress_external, 6, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - // For NPT_NP and NPH the 'reinitialize_mesh_NPT' function is being called from 'fetch_MD_cell_ingredients_restart' after calculating new Jacbdet, cell volume etc - if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)||(strcmpi(pSPARC->MDMeth,"NPH") == 0) ){ - fetch_MD_cell_ingredients_restart(pSPARC); - //Now reinitialize mesh based on calculated Jacbdet and other ingredients - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} \ No newline at end of file From 033be2100cf41bdecf60afee2b8913fe50b92779 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:13:08 -0400 Subject: [PATCH 68/87] Delete src/MD_printing_refined_cartesian.c --- src/MD_printing_refined_cartesian.c | 3566 --------------------------- 1 file changed, 3566 deletions(-) delete mode 100644 src/MD_printing_refined_cartesian.c diff --git a/src/MD_printing_refined_cartesian.c b/src/MD_printing_refined_cartesian.c deleted file mode 100644 index 2218351c..00000000 --- a/src/MD_printing_refined_cartesian.c +++ /dev/null @@ -1,3566 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include -#include -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - pSPARC->internal_pressure = 0; - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPT_NP_and_NPH(pSPARC, output_md, avgvel, maxvel, mindis); //The last four arguments: output_md, avgvel, maxvel and mindis are only passed so as to facilitate calling 'MD_QOI' or 'Print_fullMD' function from within NPT_NP or NPH subroutines - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - } - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; - } -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - } - else{ - pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; - } - - pSPARC->maxTimeIter = 100; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); - printf("herere"); - exit(EXIT_FAILURE); - } - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - if(pSPARC->NPH_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); - printf("he1"); - exit(EXIT_FAILURE); - } - } - } - - if (rank == 0) { - // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies_NPH2.log", "w"); - - if (pSPARC->fp_energy == NULL) { - fprintf(stderr, "Error: Could not open energy log file!\n"); - exit(EXIT_FAILURE); - } - - // Optional: Print a header to make the file readable in Excel/Python - fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", - "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); - fflush(pSPARC->fp_energy); - } - pSPARC->KE_save = 0.0; - fetch_MD_cell_ingredients(pSPARC, false); - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble\n"); - } - } - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; //This is computed in function: 'fetch_MD_cell_ingredients_restart' below - - if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - } - else{ - pSPARC->initialLatVecLength[0] == 1; pSPARC->initialLatVecLength[1] == 1; pSPARC->initialLatVecLength[2] == 1; - } - pSPARC->maxTimeIter = 100; - - pSPARC->KE_save = 0.0; - fetch_MD_cell_ingredients_restart(pSPARC); - - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPH")){ - pSPARC->NPT_NP_qmass = 0; - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - } - - //pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - //Calculate_ionic_stress(pSPARC); - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - if (pSPARC->RestartFlag == 0){ - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; - } -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant. -Also performs NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant. NPH in this scheme is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference for NPT_NP and NPH: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Additional Reference for NPH: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1)) { - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - //NPT_NPH_main routine - NPT_NPH_main(pSPARC, output_md, avgvel, maxvel, mindis); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ - -void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - - - // This is needed since, they will be used in function 'Cart2nonCart_transformMat' to update various quantities - for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles - pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; - } - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - -} - -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Cosine of Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - - pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; - pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; - pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; - - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); - - if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); - pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); - pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - - //Update LATVEC_SCALE and LatVec - for (int i = 0; i < 3; i++){ // LatVec just accounts for change in orientation/angles - pSPARC->LatVec[i] = ( pSPARC->full_lattice[i] / pSPARC->range_x ) * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = ( pSPARC->full_lattice[i+3] / pSPARC->range_y ) * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = ( pSPARC->full_lattice[i+6] / pSPARC->range_z) * pSPARC->initialLatVecLength[2]; - } - if (pSPARC->Flag_latvec_scale == 1){ // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - } - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - } - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell = old_cell@rotation_matrix; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate the velocity of cell lattice vectors (only useful in 1st MD step (start afresh or restart)) - else { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - else { - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - } - - temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Kinetic_energy_and_Kinetic_stress(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+2] * pSPARC->ion_vel[count*3+2]; - count++; - } - } - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - - pSPARC->KE = pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[4] + pSPARC->kinetic_stress[8]; - - //Convert kinetic stress to fractional coordinates - double temp_mat1[9]; - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat1, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat1, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else { - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - - // // Calculate kinetic energy and kinetic stress of ions - cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); - Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - cblas_dscal(3 * pSPARC->n_atom, 1.0 / pSPARC->SNOSE[2], pSPARC->ion_vel, 1); - pSPARC->KE_save = pSPARC->KE; - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3 * baro_const2, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - - double sumAllHamilTerms; - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// - - //Initialize constraint stress to 0 - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; - } -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp = pSPARC->kB * pSPARC->thermos_T; - int count; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; - - //Initialize some useful constants - double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]={0}; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; - NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; - NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; - - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else{ - NPT_NPH_ANGLES = pSPARC->NPH_ANGLES; - NPT_NPHconstraintFlag = pSPARC->NPHconstraintFlag; - NPT_NPHscaleVecs[0] = pSPARC->NPHscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPHscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPHscaleVecs[2]; - - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const3 = 1.0 / baro_const1; - - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - - pSPARC->KE = pSPARC->KE_save; - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double factor; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; - pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; - #ifdef DEBUG - if (rank == 0) { - printf("factor Eqn.18G is %12.9f\n", factor); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - } - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat_b, 3); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, pSPARC->reciprocal_lattice, 3, temp_mat_b, 3, 0.0, pSPARC->internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = (pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); - } - } - else { - if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); - } - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i < 9; i++){ - temp_mat[i] = pSPARC->internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - cblas_dcopy(3 * pSPARC->n_atom, pSPARC->forces, 1, pSPARC->ion_accel, 1); //copy the ion forces array into ion acceleration array - count = 0; - unsigned int len; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - len = 3 * pSPARC->nAtomv[ityp]; - cblas_dscal(len, 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_accel[count], 1); // Scale by 1/mass - count += len; - } - // Eqn. 18i: momentum += 0.5 * dt * S * D2C (but updating velocity in cartesian coordinates instead of momentum) - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); - //Update the kinetic energy and kinetic stress of the Ionic particles - Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); - - //Calculate internal pressure - for (int i = 0; i < 9; i++){ - pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - pSPARC->internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); - - //Update Hamiltonian - double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; - // } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; - // } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - } - } - #endif - - // For printing, convert the total internal stress and the kinetic stress to cartesian coordinates - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->total_internal_stress, 3); //Mutliplied by 2 so as to remove the effect of previous divisions by 2 in the kinetic_stress, internal_stress_fractional - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, -2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress - - cblas_dscal(3 * pSPARC->n_atom, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - pSPARC->KE_save = pSPARC->KE; - int check1 = (pSPARC->PrintMDout == 1 && !rank); - MD_QOI(pSPARC, avgvel, maxvel, mindis); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - pSPARC->KE = pSPARC->KE_save; - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper (but updating velocity in cartesian coordinates instead of momentum; they are equivalent formulation as kinetic energy and kinetic stress is consistent with this change) - // Eqn. 18a: momentum += 0.5 * dt * S * D2C - cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_energy_and_Kinetic_stress(pSPARC); - - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC); - - //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - } - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp - S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - printf("%15.7f \n", S_new); - printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - - pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - - //Eqn. 18e is implicitly solved in the below subroutine - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new, NPT_NPH_ANGLES, NPT_NPHconstraintFlag); - - //Before updating cell parameters, store the old reciprocal lattice - for (int i = 0; i < 9; i++) { temp_mat[i] = pSPARC->reciprocal_lattice[i];} - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, temp_mat_b, 3); - // Now reconvert atomic positions to cartesian coordinates, accounting change in cell size/shape (remember this are still of previous step, they have yet to be updated) - double *atom_pos_update = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); //temporary array - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, temp_mat_b, 3, 0.0, atom_pos_update, 3); - cblas_dcopy(3 * pSPARC->n_atom, atom_pos_update, 1, pSPARC->atom_pos, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, temp_mat_b, 3, 0.0, atom_pos_update, 3); - cblas_dcopy(3 * pSPARC->n_atom, atom_pos_update, 1, pSPARC->ion_vel, 1); - free(atom_pos_update); - //Update Atomic position in cartesian coordinates coordinates (Eqn. 18f in Hernandez paper) - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel, 1, pSPARC->atom_pos, 1); - //Update atomic positions and restore ionic velocities - cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); - - - //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); - pSPARC->KE_save = pSPARC->KE; - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); - } - - // Update SNOSE[0] to S_new - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_new; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// -} - - -void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - else{ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (NPT_NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (NPT_NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (NPT_NPHscaleVecs[2] == 0 && NPT_NPHconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_ANGLES, int NPT_NPHconstraintFlag){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - } - else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); - } - - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - - if (NPT_NPH_ANGLES == 0){ - if (NPT_NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (NPT_NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; i < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } - - #ifdef DEBUG - if (rank == 0) { - for (int i = 0; i < 9; i++){ - printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); - } - } - #endif - -} - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-12; // tolerance criterion for checking convergence - double baro_const0, baro_const3, baro_const5; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - - } - else{ - baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - - } - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); - #endif - } -} - - - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha \n"); - } - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } else { - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); - fprintf(output_md,":Desc_SNOSE[0]: Position variable of the thermostat\n"); - fprintf(output_md,":Desc_SNOSE[1]: Velocity variable of the thermostat\n"); - } else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell expansion). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated as: kinetic_stress (positive convention) - electronic stress - constraint stress; as per (E. Hernandez, 2001) paper - } - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_TOTSTRESS: Total internal pressure (also accounting pressure due to any constraint on cell expansion). Unit=GPa \n"); - } - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); - fprintf(output_md,":SNOSE[0]:%18.10E \n", pSPARC->SNOSE[0]); - fprintf(output_md,":SNOSE[1]:%18.10E \n", pSPARC->SNOSE[1]); - } if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(output_md,":ANGLES:\n"); - fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL:\n"); - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: \n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x / pSPARC->initialLatVecLength[0], pSPARC->range_y / pSPARC->initialLatVecLength[1], pSPARC->range_z / pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - else{ //Trigger NPT_NP or NPH ensemble stress printing - fprintf(output_md,":STRIO:\n"); - double temp_stress[6]; - temp_stress[0] = pSPARC->kinetic_stress[0]; temp_stress[1] = pSPARC->kinetic_stress[1]; temp_stress[2] = pSPARC->kinetic_stress[2]; - temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[7]; - PrintStress (pSPARC, temp_stress, output_md); //Print kinetic stress as defined in the (E. Hernandez, 2001) paper - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i]; // stress_i or ionic stress function is never called in NPT_NP or NPH ensemble, so pSPARC->stress does not include contribution from it, and thus no need to subtract stress_i from pSPARC->stress, as done in other ensembles - PrintStress (pSPARC, stress_e, output_md); - fprintf(output_md,":TOTSTRESS:\n"); //Print total internal stress accouting for the constraints in NPT_NP or NPH ensemble - temp_stress[0] = pSPARC->total_internal_stress[0]; temp_stress[1] = pSPARC->total_internal_stress[1]; temp_stress[2] = pSPARC->total_internal_stress[2]; - temp_stress[3] = pSPARC->total_internal_stress[4]; temp_stress[4] = pSPARC->total_internal_stress[5]; temp_stress[5] = pSPARC->total_internal_stress[7]; - PrintStress (pSPARC, temp_stress, output_md); - } - } - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i * CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i) * CONST_HA_BOHR3_GPA); - } - else{ //Trigger NPT_NP or NPH ensemble stress printing - double ion_kinetic_pressure; - ion_kinetic_pressure = -1.0 / 3.0 * (pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[1] + pSPARC->kinetic_stress[2]); //Kinetic stress is already multiplied by 2 - fprintf(output_md,":PRESIO: %18.10E\n", ion_kinetic_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->internal_pressure - ion_kinetic_pressure) * CONST_HA_BOHR3_GPA); - fprintf(output_md,":TOTPRES: %18.10E\n", pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); //Also accounts for pressure due to constraint stress - } - - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig * CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":PREST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the quantities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE / pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - - // Compute Ionic stress/pressure - if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - } - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old; - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - mean_internal_pressure_old = pSPARC->mean_internal_pressure; - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_internal_pressure = sqrt(fabs( ((pow(pSPARC->std_internal_pressure,2.0) + pow(mean_internal_pressure_old,2.0)) * (Count - 1) + pow(pSPARC->internal_pressure,2.0))/Count - pow(pSPARC->mean_internal_pressure,2.0) )); - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(9, sizeof(double)); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - printf("\n"); - printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP or NPH ensemble - if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":NPT_NP_SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep - fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep - fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPH_bmass); - fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); - } - fprintf(mdout,":lattice_avg_velo: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); - fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] - , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] - , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] - , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] - , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); - } - fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI ); - fprintf(mdout,":ROTATION_MATRIX: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] - , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] - , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":EXTERNAL_PRESSURE %.15g\n", pSPARC->pressure_external * 29421.02648438959); - fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * 29421.02648438959 - ,pSPARC->stress_external[1] * 29421.02648438959 - ,pSPARC->stress_external[2] * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - } - // Print temperature - fprintf(mdout,":TEL(K): %18.10E\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %18.10E\n", pSPARC->ion_T); - fprintf(mdout,":TELST(K): %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(mdout,":TIOST(K): %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(mdout,":PREST(Gpa): %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); - fprintf(mdout,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(mdout,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(mdout,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(mdout,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(mdout,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 20)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 56 + 20)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 52 + 20)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 22) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TELST(K):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_elec_T); fscanf(rst_fp,"%lf", &pSPARC->std_elec_T); - }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); - }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); - pSPARC->mean_internal_pressure /= CONST_HA_BOHR; pSPARC->std_internal_pressure /= CONST_HA_BOHR; - }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); - }else if (strcmpi(str,":KENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_KE); fscanf(rst_fp,"%lf", &pSPARC->std_KE); - }else if (strcmpi(str,":FENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_PE); fscanf(rst_fp,"%lf", &pSPARC->std_PE); - }else if (strcmpi(str,":UENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_U); fscanf(rst_fp,"%lf", &pSPARC->std_U); - }else if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_Entropy); fscanf(rst_fp,"%lf", &pSPARC->std_Entropy); - } - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_TE_ext); fscanf(rst_fp,"%lf", &pSPARC->std_TE_ext); - } - } - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[0]); - else if (strcmpi(str,":NPT_NP_SNOSE[1]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[1]); - else if (strcmpi(str,":NPT_NP_SNOSE[2]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[2]); - else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (strcmpi(str,":NPH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPH_bmass); - else if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); - } - else if (strcmpi(str,":LATTICE_AVG_VELOCITY:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[0]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[1]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[2]); - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[3]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[4]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[5]); - fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[6]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[7]); fscanf(rst_fp,"%lf", &pSPARC->lattice_avg_velo[8]); - - } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); - for (int i = 0; i < 3; i++){pSPARC->initialLatVecAngles[i] = cos(M_PI / 180 * pSPARC->initialLatVecAngles[i]);} - } else if (strcmpi(str,":CELL:") == 0) { - fscanf(rst_fp,"%lf", pSPARC->range_x); fscanf(rst_fp,"%lf", pSPARC->range_y); fscanf(rst_fp,"%lf", pSPARC->range_z); - } else if (strcmpi(str,":LatUVec:") == 0) { - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); - } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->range_x = pSPARC->initialLatVecLength[0]*pSPARC->latvec_scale_x; - pSPARC->range_y = pSPARC->initialLatVecLength[1]*pSPARC->latvec_scale_y; - pSPARC->range_z = pSPARC->initialLatVecLength[2]*pSPARC->latvec_scale_z; - } else if (strcmpi(str,":LatVec:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); - fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); - fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); - } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[6]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[7]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[8]); - } else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":EXTERNAL_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->pressure_external); - else if (strcmpi(str,":EXTERNAL_STRESS:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->stress_external[0]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[1]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[2]); - fscanf(rst_fp,"%lf", &pSPARC->stress_external[3]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[4]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[5]); - } - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->mean_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[0], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[1], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->SNOSE[2], 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Pack(&pSPARC->NPH_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - MPI_Pack(pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if (pSPARC->Flag_latvec_scale == 0){ - MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if (pSPARC->Flag_latvec_scale == 1){ - MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[0], 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[1], 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->SNOSE[2], 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPH_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - MPI_Unpack(buff, l_buff, &position, pSPARC->lattice_avg_velo, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if (pSPARC->Flag_latvec_scale == 0){ - MPI_Unpack(buff, l_buff, &position, pSPARC->LatUVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if (pSPARC->Flag_latvec_scale == 1){ - MPI_Unpack(buff, l_buff, &position, pSPARC->LatVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); - } - MPI_Unpack(buff, l_buff, &position, pSPARC->rotation_matrix, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->pressure_external, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->stress_external, 6, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - From 6b216cd26497b72d6a727718f2d4c0883e424d35 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:13:15 -0400 Subject: [PATCH 69/87] Delete src/MD_printing_refined_fractional.c --- src/MD_printing_refined_fractional.c | 3856 -------------------------- 1 file changed, 3856 deletions(-) delete mode 100644 src/MD_printing_refined_fractional.c diff --git a/src/MD_printing_refined_fractional.c b/src/MD_printing_refined_fractional.c deleted file mode 100644 index 42438d59..00000000 --- a/src/MD_printing_refined_fractional.c +++ /dev/null @@ -1,3856 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include -#include -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPT_NP_and_NPH(pSPARC, output_md, avgvel, maxvel, mindis); //The last four arguments: output_md, avgvel, maxvel and mindis are only passed so as to facilitate calling 'MD_QOI' or 'Print_fullMD' function from within NPT_NP or NPH subroutines - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - } - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - if((strcmpi(pSPARC->MDMeth,"NPT_NP") != 0) && (strcmpi(pSPARC->MDMeth,"NPH") != 0)){ // for NPT_NP and NPH, this instance is corresponding to time = t in positions and potential energies, but only time = t-dt/2 for momenta, velocities and kinetic energies, so the same function is called within NPT_NP or NPH subroutine, when all quantities are in-sync and belong to same time = t - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ - free(pSPARC->ion_vel_fractional); - free(pSPARC->Pm_ion); - } -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - } - else{ - pSPARC->initialLatVecLength[0] = 1; pSPARC->initialLatVecLength[1] = 1; pSPARC->initialLatVecLength[2] = 1; - } - - pSPARC->maxTimeIter = 100; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - if(pSPARC->NPH_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - } - - pSPARC->KE_save = 0.0; - fetch_MD_cell_ingredients(pSPARC, false); - - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble\n"); - } - } - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for fractional ionic velocity array.\n"); - exit(EXIT_FAILURE); - } - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic momentum array.\n"); - exit(EXIT_FAILURE); - } - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->maxTimeIter = 100; - - //fetch_MD_cell_ingredients_restart(pSPARC); - pSPARC->KE_save = 0.0; - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - - - if(strcmpi(pSPARC->MDMeth,"NPH")==0){ - pSPARC->NPT_NP_qmass = 0; - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - } - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - - //Calculate_ionic_stress(pSPARC); - - //Ion vel fractional memory allocation already done within 'RestartMD' function as that is being MPI communicated - pSPARC->ion_vel_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic fractional velocity array.\n"); - exit(EXIT_FAILURE); - } - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - if (pSPARC->RestartFlag == 0){ - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; pSPARC->mean_internal_pressure = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; pSPARC->std_internal_pressure = 0.0; - for (int i = 0; i < 9; i++){ - pSPARC->mean_total_internal_stress[i] = 0.0; - pSPARC->std_total_internal_stress[i] = 0.0; - } - } -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant. -Also performs NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant. NPH in this scheme is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference for NPT_NP and NPH: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Additional Reference for NPH: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPT_NP_and_NPH(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)){ - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - //NPT_NPH_main routine - NPT_NPH_main(pSPARC, output_md, avgvel, maxvel, mindis); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - -void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - int i, j, k; - - double TEMP_TOL = 1e-12; - // Construct LatUVec; - double mag; - for(i = 0; i < 3; i++){ - mag = sqrt(pow(pSPARC->full_lattice[3 * i], 2.0) - + pow(pSPARC->full_lattice[3 * i + 1], 2.0) - + pow(pSPARC->full_lattice[3 * i + 2], 2.0)); - pSPARC->LatUVec[3 * i] = pSPARC->full_lattice[3 * i]/mag; - pSPARC->LatUVec[3 * i + 1] = pSPARC->full_lattice[3 * i + 1]/mag; - pSPARC->LatUVec[3 * i + 2] = pSPARC->full_lattice[3 * i + 2]/mag; - } - - // determinant of 3x3 Jacobian - pSPARC->Jacbdet = 0.0; - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - if(i != j && j != k && k != i) - pSPARC->Jacbdet += ((i - j) * (j - k) * (k - i)/2) * pSPARC->LatUVec[3 * i] * pSPARC->LatUVec[3 * j + 1] * pSPARC->LatUVec[3 * k + 2]; - } - } - } - - if(pSPARC->Jacbdet <= 0){ - if(rank == 0) - printf("ERROR: Volume(det(jacobian)) %lf is <= 0\n", pSPARC->Jacbdet); - exit(EXIT_FAILURE); - } - - // transformation matrix for distance - for(i = 0; i < 9; i++) - pSPARC->metricT[i] = 0.0; - - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - pSPARC->metricT[3*i + j] += pSPARC->LatUVec[3*i + k] * pSPARC->LatUVec[3*j + k]; - } - } - } - - pSPARC->metricT[1] = 2 * pSPARC->metricT[1]; - pSPARC->metricT[2] = 2 * pSPARC->metricT[2]; - pSPARC->metricT[5] = 2 * pSPARC->metricT[5]; - - // transformation matrix for gradient - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - pSPARC->gradT[3*j + i] = (pSPARC->LatUVec[3 * ((j+1) % 3) + (i+1) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+2) % 3] - pSPARC->LatUVec[3 * ((j+1) % 3) + (i+2) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+1) % 3])/pSPARC->Jacbdet; - } - } - - // transformation matrix for laplacian - for(i = 0; i < 9; i++) - pSPARC->lapcT[i] = 0.0; - - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - pSPARC->lapcT[3*i + j] += pSPARC->gradT[3*i + k] * pSPARC->gradT[3*j + k]; - } - } - } - - /* Different cell types for laplacian */ - if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 11; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 12; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 13; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 14; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 15; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 16; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 17; -#ifdef DEBUG - if(!rank) - printf("\n\nCELL_TYP: %d\n\n",pSPARC->cell_typ); -#endif - /* transform the coefficiens of lapacian*/ - // int p, FDn = pSPARC->order/2; - // double dx_inv, dy_inv, dz_inv, dx2_inv, dy2_inv, dz2_inv; - // dx_inv = 1.0 / (pSPARC->delta_x); - // dy_inv = 1.0 / (pSPARC->delta_y); - // dz_inv = 1.0 / (pSPARC->delta_z); - // dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - // dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - // dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - // for (p = 0; p < FDn + 1; p++) { - // pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - // pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - // pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - // pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - // pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - // pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - // pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - // pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - // pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - // pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - // pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - // pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - // } - // TODO: Find maximum eigenvalue of Hamiltionian (= max. eigvalue of -0.5 lap) for non orthogonal periodic systems -} - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ - -void fetch_MD_cell_ingredients_restart(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - if (pSPARC->Flag_latvec_scale == 0){ - for (int i = 0; i < 3; i++) { - pSPARC->full_lattice[i] = pSPARC->LatUVec[i] * pSPARC->range_x; - pSPARC->full_lattice[i+3] = pSPARC->LatUVec[i + 3] * pSPARC->range_y; - pSPARC->full_lattice[i+6] = pSPARC->LatUVec[i + 6] * pSPARC->range_z; - } - } - else{ - for (int i = 0; i < 3; i++) { - pSPARC->full_lattice[i] = pSPARC->LatVec[i] * pSPARC->latvec_scale_x; - pSPARC->full_lattice[i+3] = pSPARC->LatVec[i+3] * pSPARC->latvec_scale_y; - pSPARC->full_lattice[i+6] = pSPARC->LatVec[i+6] * pSPARC->latvec_scale_z; - } - - } - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - if (pSPARC->Flag_latvec_scale == 1){ - pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); - pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); - pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2]* pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - } - else{ - pSPARC->initialLatVecLength[0] = 1; pSPARC->initialLatVecLength[1] = 1; pSPARC->initialLatVecLength[2] = 1; - } - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat_MD(pSPARC); - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // printf("Volume cell %lf \n",pSPARC->volumeCell); - // printf("range_x %lf \n",pSPARC->range_x); - // printf("range_y %lf \n",pSPARC->range_y); - // printf("range_z %lf \n",pSPARC->range_z); - - // for (int i = 0; i < 9; i++){ - // printf("FUll lattice[%d] is %lf \n",i,pSPARC->full_lattice[i]); - // } - - if (pSPARC->Flag_latvec_scale == 1){ - for (int i = 0; i < 9; i++){ - printf("LatVec[%d] is %lf \n",i,pSPARC->LatVec[i]); - } - } - if (pSPARC->Flag_latvec_scale == 0){ - for (int i = 0; i < 9; i++){ - printf("LatUVec[%d] is %lf \n",i,pSPARC->LatUVec[i]); - } - } - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - printf("here"); -} - -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Cosine of Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - - pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; - pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; - pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; - - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); - - if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); - pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); - pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat_MD(pSPARC); - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - - } - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice@new_cell as we want: new_cell@Rotation_matrix.T = old_cell; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate the velocity of cell lattice vectors (only useful in 1st MD step (start afresh or restart)) - else { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - else { - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - } - - temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double vector[3]={0.0}; - pSPARC->KE = 0.0; - - int count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, &pSPARC->Pm_ion[count*3], 1, 0.0, vector, 1); - pSPARC->KE += cblas_ddot(3, vector, 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - count++; - } - } - - pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); -} - - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3] * pSPARC->ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+1] * pSPARC->ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * pSPARC->ion_vel_fractional[count*3+2] * pSPARC->ion_vel_fractional[count*3+2]; - count++; - } - } - - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else { - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - - // Calculating kinetic energy of ions - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->ion_vel_fractional, 3); - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel_fractional, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->metric_tensor, 3, 0.0, pSPARC->Pm_ion, 3); - int count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - cblas_dscal(3 * pSPARC->nAtomv[ityp], pSPARC->Mass[ityp], &pSPARC->Pm_ion[count], 1); - count = count + 3 * pSPARC->nAtomv[ityp]; - } - // Calculate kinetic energy and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - pSPARC->KE_save = pSPARC->KE; - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3 * baro_const2, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - - double sumAllHamilTerms; - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - - #ifdef DEBUG - if (rank == 0) { - printf("within init"); - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - } - } - #endif - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// - - //Initialize constraint stress to 0 - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; - } -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp = pSPARC->kB * pSPARC->thermos_T; - int count; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; - - //Initialize some useful constants - double baro_const1; int NPT_NPH_ANGLES; int NPT_NPHconstraintFlag; int NPT_NPHscaleVecs[3]={0}; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - NPT_NPH_ANGLES = pSPARC->NPT_NP_ANGLES; - NPT_NPHconstraintFlag = pSPARC->NPTconstraintFlag; - NPT_NPHscaleVecs[0] = pSPARC->NPTscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPTscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPTscaleVecs[2]; - - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else{ - NPT_NPH_ANGLES = pSPARC->NPH_ANGLES; - NPT_NPHconstraintFlag = pSPARC->NPHconstraintFlag; - NPT_NPHscaleVecs[0] = pSPARC->NPHscaleVecs[0]; NPT_NPHscaleVecs[1] = pSPARC->NPHscaleVecs[1]; NPT_NPHscaleVecs[2] = pSPARC->NPHscaleVecs[2]; - - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const3 = 1.0 / baro_const1; - - // printf("QMASS: %lf\n",pSPARC->NPT_NP_qmass); - // printf("SNOSE[0] %lf \n",pSPARC->SNOSE[0]); - // printf("SNOSE[1] %lf \n",pSPARC->SNOSE[1]); - // printf("SNOSE[2] %lf \n",pSPARC->SNOSE[2]); - // printf("KE %lf \n",pSPARC->KE); - // printf("Kbaro %lf \n",pSPARC->Kbaro); - // printf("Ubaro %lf \n",pSPARC->Ubaro); - // printf("InitHamil %lf \n",pSPARC->init_Hamil_NPT_NP); - // //; - // if (rank == 0){ - // printf(":Pm_ion:\n"); - // for(int atm = 0; atm < pSPARC->n_atom; atm++){ - // printf("%18.10E %18.10E %18.10E\n", pSPARC->Pm_ion[3 * atm], pSPARC->Pm_ion[3 * atm + 1], pSPARC->Pm_ion[3 * atm + 2]); - // } - // } - // printf("Intial angles %18.10E %18.10E %18.10E\n", pSPARC->initialLatVecAngles[0], pSPARC->initialLatVecAngles[1], pSPARC->initialLatVecAngles[2]); - // exit(EXIT_FAILURE); - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double factor; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - factor = (pSPARC->KE - pSPARC->Etot - pSPARC->dof * ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; - pSPARC->SNOSE[1] += 0.5 * factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; - #ifdef DEBUG - if (rank == 0) { - printf("factor Eqn.18G is %12.9f\n", factor); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - } - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, pSPARC->reciprocal_lattice, 3, 0.0, temp_mat_b, 3); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, pSPARC->reciprocal_lattice, 3, temp_mat_b, 3, 0.0, pSPARC->internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = (pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); - } - } - else { - if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC, NPT_NPHconstraintFlag, NPT_NPHscaleVecs); - } - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i < 9; i++){ - temp_mat[i] = pSPARC->internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - double *ion_forces_fractional = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (ion_forces_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for ionic forces fractional array.\n"); - exit(EXIT_FAILURE); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->forces, 3, pSPARC->full_lattice, 3, 0.0, ion_forces_fractional, 3); - // Eqn. 18i: momentum += 0.5 * dt * S * D2C - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); - count += 3 * pSPARC->nAtomv[ityp]; - } - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); - - for (int i = 0; i < 9; i++){ - pSPARC->total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - pSPARC->internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); - - //Update Hamiltonian - double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; - // } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; - // } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - } - } - #endif - - // For printing, convert the total internal stress, constraint stress and the kinetic stress to cartesian coordinates - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->total_internal_stress, 3, 0.0, temp_mat, 3); //Already divided by volume earlier - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->total_internal_stress, 3); //Mutliplied by 2 so as to remove the effect of previous divisions by 2 in the kinetic_stress, internal_stress_fractional - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->kinetic_stress, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->kinetic_stress, 3); //Mutliplied by 2 so as to remove the effect of previous division by 2 in the kinetic_stress, and negated so as to follow SPARC convention of ion-kinetic stress - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / pSPARC->volumeCell, pSPARC->full_lattice, 3, pSPARC->constraint_stress, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 2.0, temp_mat, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->constraint_stress, 3); - - - - // Obtain updated velocities in cartesian coordinates for use in MD_QOI function - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0 / pSPARC->SNOSE[0], pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); - int check1 = (pSPARC->PrintMDout == 1 && !rank); - MD_QOI(pSPARC, avgvel, maxvel, mindis); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], ion_forces_fractional, 1, pSPARC->Pm_ion, 1); - free(ion_forces_fractional); - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->Pm_ion, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->ion_vel_fractional, 3); - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - cblas_dscal(3 * pSPARC->nAtomv[ityp], 1.0 / pSPARC->Mass[ityp], &pSPARC->ion_vel_fractional[count], 1); - count = count + 3 * pSPARC->nAtomv[ityp]; - } - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); - - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC); - - //Now impose the constraints on it - if (NPT_NPHscaleVecs[2] == 0){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - } - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp - S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - if (rank == 0){ - printf("%15.7f \n", S_new); - printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - - pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - - //Eqn. 18e is implicitly solved in the below subroutine - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new, NPT_NPH_ANGLES, NPT_NPHconstraintFlag); - - //Before updating cell parameters, convert cartesian atomic position coordinates to fractional - double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->atom_pos, 3, pSPARC->reciprocal_lattice, 3, 0.0, atom_pos_fractional, 3); - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - //Update Atomic position in fractional coordinates (Eqn. 18f in Hernandez paper) - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * (1.0 / pSPARC->SNOSE[0] + 1.0 / S_new), pSPARC->ion_vel_fractional, 1, atom_pos_fractional, 1); - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, atom_pos_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->atom_pos, 3); - free(atom_pos_fractional); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, pSPARC->n_atom, 3, 3, 1.0, pSPARC->ion_vel_fractional, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->ion_vel, 3); - //Update atomic positions and restore ionic velocities - cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel, 1); - //cblas_dscal(3 * pSPARC->n_atom, 1.0 / S_new, pSPARC->ion_vel_fractional, 1); - - - //Update the Kinetic and Potential energy of the barostat based on new metric tensor and new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); - pSPARC->KE_save = pSPARC->KE; - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_new * S_new ); - } - - // Update SNOSE[0] to S_new - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_new; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// -} - - -void compute_constraint_stress(SPARC_OBJ *pSPARC, int NPT_NPHconstraintFlag, int *NPT_NPHscaleVecs){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - else{ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (NPT_NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (NPT_NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (NPT_NPHscaleVecs[2] == 0 ){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (NPT_NPHscaleVecs[0] == 0 && NPT_NPHscaleVecs[1] == 0 && NPT_NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new, int NPT_NPH_ANGLES, int NPT_NPHconstraintFlag){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - } - else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); - } - - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++){ - if (rank == 0){ - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - } - } - - if (NPT_NPH_ANGLES == 0){ - if (NPT_NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (NPT_NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; i < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } - - #ifdef DEBUG - if (rank == 0) { - for (int i = 0; i < 9; i++){ - printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); - } - } - #endif - -} - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-12; // tolerance criterion for checking convergence - double baro_const0, baro_const3, baro_const5; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - - } - else{ - baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - - } - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = pSPARC->internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++){ - if (rank == 0){ - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); - #endif - } -} - - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha \n"); - } - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); - fprintf(output_md,":Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 \n"); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = 1 \n",pSPARC->MDMeth); - } else { - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during %s ensemble (has same magnitude as initial LatVec). Unit = Bohr \n",pSPARC->MDMeth); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha \n"); - fprintf(output_md,":Desc_SNOSE[0]: Position variable of the thermostat\n"); - fprintf(output_md,":Desc_SNOSE[1]: Velocity variable of the thermostat\n"); - } else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated different in NPT_NP and NPH ensemble (basically not explicitly subtracting center of mass velocity, but assuming it to be 0, as per the (E.Hernandez, 2001) paper formula) - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell expansion). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); //Calculated as: kinetic_stress (positive convention) - electronic stress - constraint stress; as per (E. Hernandez, 2001) paper - } - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_TOTSTRESS: Total internal pressure (also accounting pressure due to any constraint on cell expansion). Unit=GPa \n"); - } - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP); - fprintf(output_md,":SNOSE[0]:%18.10E \n", pSPARC->SNOSE[0]); - fprintf(output_md,":SNOSE[1]:%18.10E \n", pSPARC->SNOSE[1]); - } if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(output_md,":ANGLES:\n"); - fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(output_md,":VOLUME: %18.10E\n", pSPARC->volumeCell); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL:\n"); - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: \n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x / pSPARC->initialLatVecLength[0], pSPARC->range_y / pSPARC->initialLatVecLength[1], pSPARC->range_z / pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - else{ //Trigger NPT_NP or NPH ensemble stress printing - fprintf(output_md,":STRIO:\n"); - double temp_stress[6]; - temp_stress[0] = pSPARC->kinetic_stress[0]; temp_stress[1] = pSPARC->kinetic_stress[1]; temp_stress[2] = pSPARC->kinetic_stress[2]; - temp_stress[3] = pSPARC->kinetic_stress[4]; temp_stress[4] = pSPARC->kinetic_stress[5]; temp_stress[5] = pSPARC->kinetic_stress[8]; - PrintStress (pSPARC, temp_stress, output_md); //Print kinetic stress as defined in the (E. Hernandez, 2001) paper - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i]; // stress_i or ionic stress function is never called in NPT_NP or NPH ensemble, so pSPARC->stress does not include contribution from it, and thus no need to subtract stress_i from pSPARC->stress, as done in other ensembles - PrintStress (pSPARC, stress_e, output_md); - fprintf(output_md,":CONSTRESS:\n"); - temp_stress[0] = pSPARC->constraint_stress[0]; temp_stress[1] = pSPARC->constraint_stress[1]; temp_stress[2] = pSPARC->constraint_stress[2]; - temp_stress[3] = pSPARC->constraint_stress[4]; temp_stress[4] = pSPARC->constraint_stress[5]; temp_stress[5] = pSPARC->constraint_stress[8]; - PrintStress (pSPARC, temp_stress, output_md); - fprintf(output_md,":TOTSTRESS:\n"); //Print total internal stress accouting for the constraints in NPT_NP or NPH ensemble - temp_stress[0] = pSPARC->total_internal_stress[0]; temp_stress[1] = pSPARC->total_internal_stress[1]; temp_stress[2] = pSPARC->total_internal_stress[2]; - temp_stress[3] = pSPARC->total_internal_stress[4]; temp_stress[4] = pSPARC->total_internal_stress[5]; temp_stress[5] = pSPARC->total_internal_stress[8]; - PrintStress (pSPARC, temp_stress, output_md); - } - } - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i * CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i) * CONST_HA_BOHR3_GPA); - } - else{ //Trigger NPT_NP or NPH ensemble stress printing - double ion_kinetic_pressure, constraint_pressure; - ion_kinetic_pressure = 1.0 / 3.0 * (pSPARC->kinetic_stress[0] + pSPARC->kinetic_stress[4] + pSPARC->kinetic_stress[8]); //Kinetic stress is already multiplied by 2 - constraint_pressure = 1.0 / 3.0 * (pSPARC->constraint_stress[0] + pSPARC->constraint_stress[4] + pSPARC->constraint_stress[8]); //Constraint stress is already multiplied by 2 - fprintf(output_md,":PRESIO: %18.10E\n", ion_kinetic_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->internal_pressure - ion_kinetic_pressure + constraint_pressure) * CONST_HA_BOHR3_GPA); - fprintf(output_md,":CONPRES: %18.10E\n", constraint_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":TOTPRES: %18.10E\n", pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); //Also accounts for pressure due to constraint stress - } - - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig * CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":PREST: %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":MEAN_TOTSTRESS:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->mean_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[2] * CONST_HA_BOHR3_GPA - , pSPARC->mean_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[5] * CONST_HA_BOHR3_GPA - , pSPARC->mean_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->mean_total_internal_stress[8] * CONST_HA_BOHR3_GPA); - fprintf(output_md,":STD_TOTSTRESS:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->std_total_internal_stress[0] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[1] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[2] * CONST_HA_BOHR3_GPA - , pSPARC->std_total_internal_stress[3] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[4] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[5] * CONST_HA_BOHR3_GPA - , pSPARC->std_total_internal_stress[6] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[7] * CONST_HA_BOHR3_GPA, pSPARC->std_total_internal_stress[8] * CONST_HA_BOHR3_GPA); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the quantities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE / pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - - // Compute Ionic stress/pressure - if(strcmpi(pSPARC->MDMeth,"NPT_NP") != 0 && strcmpi(pSPARC->MDMeth,"NPH") != 0){ - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - } - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old, mean_total_internal_stress_old[9]; - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - mean_internal_pressure_old = pSPARC->mean_internal_pressure; - for (int i = 0; i < 9; i++){mean_total_internal_stress_old[i] = pSPARC->mean_total_internal_stress[i];} - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; - for (int i = 0; i < 9; i++){pSPARC->mean_total_internal_stress[i] = (mean_total_internal_stress_old[i] * (Count - 1) + pSPARC->total_internal_stress[i]) / Count;} - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_internal_pressure = sqrt(fabs( ((pow(pSPARC->std_internal_pressure,2.0) + pow(mean_internal_pressure_old,2.0)) * (Count - 1) + pow(pSPARC->internal_pressure,2.0))/Count - pow(pSPARC->mean_internal_pressure,2.0) )); - for (int i = 0; i < 9; i++){pSPARC->std_total_internal_stress[i] = sqrt(fabs( ((pow(pSPARC->std_total_internal_stress[i],2.0) + pow(mean_total_internal_stress_old[i],2.0)) * (Count - 1) + pow(pSPARC->total_internal_stress[i],2.0))/Count - pow(pSPARC->mean_total_internal_stress[i],2.0) ));} - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(9, sizeof(double)); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - printf("\n"); - printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - fprintf(mdout,":Pm_ion:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->Pm_ion[3 * atm], pSPARC->Pm_ion[3 * atm + 1], pSPARC->Pm_ion[3 * atm + 2]); - } - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP or NPH ensemble - if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":NPT_NP_SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter at current timestep - fprintf(mdout,":NPT_NP_SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":NPT_NP_SNOSE[2]: %.15g\n", pSPARC->SNOSE[2]); // value of virtual thermal parameter at previous timestep - fprintf(mdout,":NPT_NP_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPH_bmass); - fprintf(mdout,":NPH_INIT_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); - } - fprintf(mdout,":KE: %.15g\n",pSPARC->KE); - fprintf(mdout,":Kbaro: %.15g\n",pSPARC->Kbaro); - fprintf(mdout,":Ubaro: %.15g\n",pSPARC->Ubaro); - fprintf(mdout,":kinetic_stress: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->kinetic_stress[0], pSPARC->kinetic_stress[1], pSPARC->kinetic_stress[2] - , pSPARC->kinetic_stress[3], pSPARC->kinetic_stress[4], pSPARC->kinetic_stress[5] - , pSPARC->kinetic_stress[6], pSPARC->kinetic_stress[7], pSPARC->kinetic_stress[8]); - fprintf(mdout,":Pm_metric_tensor: \n %.15g %.15g %.15g \n %.15g %.15g %.15g \n %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x, pSPARC->range_y, pSPARC->range_z); - fprintf(mdout,":LatUVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0], pSPARC->LatUVec[1], pSPARC->LatUVec[2] - , pSPARC->LatUVec[3], pSPARC->LatUVec[4], pSPARC->LatUVec[5] - , pSPARC->LatUVec[6], pSPARC->LatUVec[7], pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0], pSPARC->LatVec[1], pSPARC->LatVec[2] - , pSPARC->LatVec[3], pSPARC->LatVec[4], pSPARC->LatVec[5] - , pSPARC->LatVec[6], pSPARC->LatVec[7], pSPARC->LatVec[8]); - } - fprintf(mdout,":INITIAL_ANGLES: %18.10E %18.10E %18.10E\n", acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI, acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI ); - fprintf(mdout,":ROTATION_MATRIX: \n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->rotation_matrix[0], pSPARC->rotation_matrix[1], pSPARC->rotation_matrix[2] - , pSPARC->rotation_matrix[3], pSPARC->rotation_matrix[4], pSPARC->rotation_matrix[5] - , pSPARC->rotation_matrix[6], pSPARC->rotation_matrix[7], pSPARC->rotation_matrix[8]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":EXTERNAL_PRESSURE: %.15g\n", pSPARC->pressure_external * CONST_HA_BOHR3_GPA); - fprintf(mdout,":EXTERNAL_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",pSPARC->stress_external[0] * CONST_HA_BOHR3_GPA - ,pSPARC->stress_external[1] * CONST_HA_BOHR3_GPA - ,pSPARC->stress_external[2] * CONST_HA_BOHR3_GPA - ,pSPARC->stress_external[3] * CONST_HA_BOHR3_GPA - ,pSPARC->stress_external[4] * CONST_HA_BOHR3_GPA - ,pSPARC->stress_external[5] * CONST_HA_BOHR3_GPA); - } - // Print temperature - fprintf(mdout,":TEL(K): %18.10E\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %18.10E\n", pSPARC->ion_T); - fprintf(mdout,":TELST(K): %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(mdout,":TIOST(K): %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(mdout,":PREST(Gpa): %18.10E %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA, pSPARC->std_internal_pressure * CONST_HA_BOHR3_GPA); - fprintf(mdout,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(mdout,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(mdout,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(mdout,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(mdout,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - printf("\nCannot allocate memory for ion momentum array!\n"); - exit(EXIT_FAILURE); - } - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9 + 20)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 56 + 32)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - l_buff = 2 * sizeof(int) + (9 * pSPARC->n_atom + (5 + 52 + 32)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5 + 22) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - } - } else if (strcmpi(str,":V(Bohr/atu):") == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - } - } else if (strcmpi(str,":Pm_ion:") == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->Pm_ion[3 * atm], &pSPARC->Pm_ion[3 * atm + 1], &pSPARC->Pm_ion[3 * atm + 2]); - } - } - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TELST(K):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_elec_T); fscanf(rst_fp,"%lf", &pSPARC->std_elec_T); - }else if (strcmpi(str,":TIOST(K):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_ion_T); fscanf(rst_fp,"%lf", &pSPARC->std_ion_T); - }else if (strcmpi(str,":PREST(Gpa):") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_internal_pressure); fscanf(rst_fp,"%lf", &pSPARC->std_internal_pressure); - pSPARC->mean_internal_pressure /= CONST_HA_BOHR3_GPA; pSPARC->std_internal_pressure /= CONST_HA_BOHR3_GPA; - }else if (strcmpi(str,":TENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_TE); fscanf(rst_fp,"%lf", &pSPARC->std_TE); - }else if (strcmpi(str,":KENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_KE); fscanf(rst_fp,"%lf", &pSPARC->std_KE); - }else if (strcmpi(str,":FENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_PE); fscanf(rst_fp,"%lf", &pSPARC->std_PE); - }else if (strcmpi(str,":UENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_U); fscanf(rst_fp,"%lf", &pSPARC->std_U); - }else if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_Entropy); fscanf(rst_fp,"%lf", &pSPARC->std_Entropy); - } - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - if (strcmpi(str,":TSENST:") == 0 && pSPARC->RestartFlag == 1){ - fscanf(rst_fp,"%lf", &pSPARC->mean_TE_ext); fscanf(rst_fp,"%lf", &pSPARC->std_TE_ext); - } - } - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (strcmpi(str,":NPT_NP_SNOSE[0]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[0]); - else if (strcmpi(str,":NPT_NP_SNOSE[1]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[1]); - else if (strcmpi(str,":NPT_NP_SNOSE[2]:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->SNOSE[2]); - else if (strcmpi(str,":NPT_NP_INIT_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - if (strcmpi(str,":NPH_INIT_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPH); - } - if (strcmpi(str,":KE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->KE); - else if (strcmpi(str,":Kbaro:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->Kbaro); - else if (strcmpi(str,":Ubaro:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->Ubaro); - else if (strcmpi(str,":kinetic_stress:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[0]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[1]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[2]); - fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[3]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[4]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[5]); - fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[6]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[7]); fscanf(rst_fp,"%lf", &pSPARC->kinetic_stress[8]); - } else if (strcmpi(str,":Pm_metric_tensor:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[0]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[1]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[2]); - fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[3]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[4]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[5]); - fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[6]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[7]); fscanf(rst_fp,"%lf", &pSPARC->Pm_metric_tensor[8]); - } else if (strcmpi(str,":INITIAL_ANGLES:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[0]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[1]); fscanf(rst_fp,"%lf", &pSPARC->initialLatVecAngles[2]); - for (int i = 0; i < 3; i++){pSPARC->initialLatVecAngles[i] = cos(M_PI / 180 * pSPARC->initialLatVecAngles[i]);} - } else if (strcmpi(str,":CELL:") == 0) { - fscanf(rst_fp,"%lf", &pSPARC->range_x); fscanf(rst_fp,"%lf", &pSPARC->range_y); fscanf(rst_fp,"%lf", &pSPARC->range_z); - } else if (strcmpi(str,":LatUVec:") == 0) { - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[2]); - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[5]); - fscanf(rst_fp,"%lf", &pSPARC->LatUVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatUVec[8]); - } else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_x); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_y); fscanf(rst_fp,"%lf", &pSPARC->latvec_scale_z); - - fscanf(rst_fp, "%*[^\n]\n"); - } else if (strcmpi(str,":LatVec:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->LatVec[0]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[1]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[2]); - fscanf(rst_fp,"%lf", &pSPARC->LatVec[3]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[4]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[5]); - fscanf(rst_fp,"%lf", &pSPARC->LatVec[6]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[7]); fscanf(rst_fp,"%lf", &pSPARC->LatVec[8]); - } else if (strcmpi(str,":ROTATION_MATRIX:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[0]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[1]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[2]); - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[3]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[4]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[5]); - fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[6]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[7]); fscanf(rst_fp,"%lf", &pSPARC->rotation_matrix[8]); - } else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":EXTERNAL_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->pressure_external); - else if (strcmpi(str,":EXTERNAL_STRESS:") == 0){ - fscanf(rst_fp,"%lf", &pSPARC->stress_external[0]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[1]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[2]); - fscanf(rst_fp,"%lf", &pSPARC->stress_external[3]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[4]); fscanf(rst_fp,"%lf", &pSPARC->stress_external[5]); - } - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - MPI_Pack(pSPARC->Pm_ion, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_internal_pressure, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_TE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_PE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_U, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->mean_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_Entropy, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->mean_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->std_TE_ext, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(pSPARC->SNOSE, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Pack(&pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - MPI_Pack(&pSPARC->KE, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->Kbaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->Ubaro, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->kinetic_stress, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if (pSPARC->Flag_latvec_scale == 0){ - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->LatUVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if (pSPARC->Flag_latvec_scale == 1){ - MPI_Pack(&pSPARC->latvec_scale_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->latvec_scale_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->latvec_scale_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->LatVec, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - MPI_Pack(pSPARC->rotation_matrix, 9, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->pressure_external, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->stress_external, 6, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - if ((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - MPI_Unpack(buff, l_buff, &position, pSPARC->Pm_ion, 3 * pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - } - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_internal_pressure, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_PE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_U, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_Entropy, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->mean_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->std_TE_ext, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)){ - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, pSPARC->SNOSE, 3, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if (strcmpi(pSPARC->MDMeth,"NPH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPH, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - MPI_Unpack(buff, l_buff, &position, &pSPARC->KE, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->Kbaro, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->Ubaro, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->kinetic_stress, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->Pm_metric_tensor, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->initialLatVecAngles, 3, MPI_DOUBLE, MPI_COMM_WORLD); - if (pSPARC->Flag_latvec_scale == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->LatUVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if (pSPARC->Flag_latvec_scale == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->latvec_scale_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->LatVec, 9, MPI_DOUBLE, MPI_COMM_WORLD); - } - MPI_Unpack(buff, l_buff, &position, pSPARC->rotation_matrix, 9, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->pressure_external, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->stress_external, 6, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0)) { // For NPT_NP and NPH the 'reinitialize_mesh_NPT' function is being called from 'fetch_MD_cell_ingredients_restart' after calculating new Jacbdet, cell volume etc - reinitialize_mesh_NPT(pSPARC); - } - if((strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)||(strcmpi(pSPARC->MDMeth,"NPH") == 0) ){ - fetch_MD_cell_ingredients_restart(pSPARC); - //Now reinitialize mesh based on calculated Jacbdet and other ingredients - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - From b30ac3c1ed160fc3641302f512c876020f09cc7a Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:13:22 -0400 Subject: [PATCH 70/87] Delete src/MD_updated.c --- src/MD_updated.c | 3507 ---------------------------------------------- 1 file changed, 3507 deletions(-) delete mode 100644 src/MD_updated.c diff --git a/src/MD_updated.c b/src/MD_updated.c deleted file mode 100644 index 9c7eb4ea..00000000 --- a/src/MD_updated.c +++ /dev/null @@ -1,3507 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include - -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,":MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - NPT_NP(pSPARC); - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - - //Calculate metric_tensor G, reciprocal metric tensor, angles between lattice vectors, rotation matrix - fetch_MD_cell_ingredients(pSPARC, false); - - pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i1 = 0; i1 < 6; i1++){ - pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable. Using a zero mass would resemble NPH ensemble, if this is the case then please choose MD_METHOD as NPH \n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MdMeth,"NPH")){ - pSPARC->NPT_NPH_qmass = 0; - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble. If choosing MD_method as NPH with nonzero thermostat mass, it would be automatically set to zero at this point\n"); - } - } - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - fetch_MD_cell_ingredients(pSPARC, false); - - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i1 = 0; i1 < 6; i1++){ - pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MdMeth,"NPH")){ - pSPARC->NPT_NPH_qmass = 0 - } - - Calculate_ionic_stress(pSPARC); - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlog v * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -*/ -void NPT_NP(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant -This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPH(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row, col; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]) - - if (update_cell == true){ - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->rotation_matrix , 3, new_cell, 3, 0.0, pSPARC->full_lattice, 3); - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt(pSPARC->metric_tensor[0]); - pSPARC->range_y = sqrt(pSPARC->metric_tensor[4]); - pSPARC->range_z = sqrt(pSPARC->metric_tensor[8]); - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // Update new angles between lattice vectors - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - //Update reciprocal lattice vectors, reciprocal metric tensor - - } - - for (int i = 0; i<9; i++){ - old_cell[i] = pSPARC->full_lattice[i] - } - - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9] - double S_inv[9] = {0} - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3,3,old_cell,3,S,U,3,VT,3,superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(cblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; - cblas_dgemm(CblasRowMajor, CblasTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate its the vecocity of cell lattice vectors - else if { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - pSPARC->lattice_avg_velo[i] = 0.0; - } - - temp_mat_2[0] = temp_mat_3[0] / (2.0 * new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->rotation_matrix, 3, temp_mat_2, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int count = 0; - - pSPARC->KE = 0.0; - int ityp, atm; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); - count ++; - } - } - pSPARC->KE = pSPARC->KE / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]); - double temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); -} - - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ - double kinetic_stress[9] = {0.0}; - - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - free(ion_vel_fractional); - - kinetic_stress[3] = kinetic_stress[1]; - kinetic_stress[6] = kinetic_stress[2]; - kinetic_stress[7] = kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), kinetic_stress, 1); - - for (int i = 0; i < 9; i++){ - pSPARC->total_internal_stress[i] = ( kinetic_stress[i] - pSPARC->internal_stress[i][i] - pSPARC->constraint_stress) - } - - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); - - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); - -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - double ktemp; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // Calculating kinetic energy of ions - int ityp, atm; - cblas_dscal(pSPARC->n_atom*3,pSPARC->SNOSE[2],pSPARC->ion_vel); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(pSPARC->n_atom*3, baro_const1, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b,1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9,pSPARC->external_stress_lattice,1,pSPARC->metric_tensor,1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - - //Initialize some useful constants - double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - - double sumAllHamilTerms = pSPARC->Etot;//Potential; Term 2 in Eqn.10 in Hernandez paper - sumAllHamilTerms += pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; - } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - #endif - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// - - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - ktemp = pSPARC->kB * pSPARC->thermos_T; - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; - pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - } - - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; - - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: so reciprocal lattice vectors are columns) - for (int i = 0; i<9; i++){ - temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3,pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5*pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i<9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5*pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - if (ISIF == 10){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - - if (ISIF == 11){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9,temp_mat_a, 1, temp_mat_b,1);//Kinetic - pSPARC->Ubaro = 0.5 * cblas_ddot(9,pSPARC->external_stress_lattice,1,pSPARC->metric_tensor,1); //Potential - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - double thermo_const0 = pSPARC->MD_dt*pSPARC->SNOSE[0] / 2.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); - - //Now write Intenal pressure, external pressure to a file - - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - //Calculate/Update total energy (Hamiltonian) - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - double constant_of_motion = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); - //Optionall write all individual energy contributions to the Hamiltonian to an output file - - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); - - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC); - - //Now impose the constraints on it - if (ISIF == 10){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - - if (ISIF == 11){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - ktemp = pSPARC->kB * pSPARC->thermos_T; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * (log(pSPARC->SNOSE[0])+1) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor*pSPARC->MD_dt/pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - exit(EXIT_FAILURE); - } - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("Sv_NPT_NP in the 2nd half step is %12.9f\n", pSPARC->Sv_NPT_NP); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = 1.0; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT ensemble - S_temp = pSPARC->SNOSE[0]; - - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp-S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], - new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); - printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); - - //Before updating cell parameters, compute atom positions in fractional coordinates - double *atom_pos_fractional = (double *)calloc(3 * n_atoms, sizeof(double)); - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); - count++ - } - - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * pSPARC->atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * pSPARC->atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[6] * pSPARC->atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); - count++; - } - free(atom_pos_fractional); - - //Update atomic positions and restore ionic velocities - int count = 0; - int atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * (pSPARC->ion_vel[count * 3] / pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3] / S_new); // - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * (pSPARC->ion_vel[count * 3 + 1] / pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 1] / S_new); // - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * (pSPARC->ion_vel[count * 3 + 2] / pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 2] / S_new); // - pSPARC->ion_vel[count * 3] /= pSPARC->SNOSE[0]; - pSPARC->ion_vel[count * 3 + 1] /= pSPARC->SNOSE[0]; - pSPARC->ion_vel[count * 3 + 2] /= pSPARC->SNOSE[0]; - count ++; - } - - //Update kinetic energy and kinetic stress - pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; - } - - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_new; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - - -} - - - - -void compute_constraint_stress(SPARC_OBJ *pSPARC){ - - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (ISIF == 8){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (ISIF == 9){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (ISIF == 10){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - // Only |c| varies, |a| and |b| are fixed; and all angles between lattice vectors are FIXED - else if (ISIF == 11){ - gpig[0] = 0; - gpig[4] = 0; - } - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) / pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3,constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0/baro_const4, gpi, 3,pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * (temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * (temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * (temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row][0], - new_metric_tensor[row][1], new_metric_tensor[row][2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - - if (ISIF >= 7){ - if (ISIF == 8){ - new_metric_tensor[0] = ( new_metric_tensor[0] + ne w_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (ISIF == 9){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; mt1 < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } -} - - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ - - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-12; // tolerance criterion for checking convergence - double baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const3 = 0.5 / baro_const0; - double baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, - temp_Pm_metric_tensor, 3, - pSPARC->metric_tensor, 3, - 0.0, temp_mat_1, 3); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, - temp_mat_1, 3, - temp_Pm_metric_tensor, 3, - 0.0, temp_mat_2, 3); - - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int ic1 = 0; ic1 < 9; ic1++){ - if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], - new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - } -} - - - - -void updateMomentum_FirstHalf(SPARC_OBJ *pSPARC) { - double ktemp; - double Ga1[3]; - double B[3]; - double Ga3[3]; - double PmA[3]; - - - - - - // update momentum of barostat variables in a half step - for (int i = 0; i < 3; i++){ - if (pSPARC->NPTscaleVecs[i] == 1) { - Ga1[i] = innerControlStress[i] * pSPARC->volumeCell / 2.0 / pSPARC->G_NPT_NP[i]; - B[i] = 1.0 / (pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) * pow(pSPARC->Pm_NPT_NP[i],2.0) * pSPARC->G_NPT_NP[i]; - Ga3[i] = (pSPARC->prtarget * pSPARC->volumeCell / 2.0 - pSPARC->Kbaro) / pSPARC->G_NPT_NP[i]; - PmA[i] = Ga1[i] + B[i] + Ga3[i]; - pSPARC->Pm_NPT_NP[i] -= pSPARC->MD_dt * pSPARC->S_NPT_NP / 2.0 * PmA[i]; - #ifdef DEBUG - if (rank == 0){ - // printf("pSPARC->pres is %12.9f, pSPARC->pres_i is %12.9f, pSPARC->volumeCell is %12.9f, pSPARC->G_NPT_NP[%d] is %12.9f\n", pSPARC->pres, pSPARC->pres_i, pSPARC->volumeCell, i, pSPARC->G_NPT_NP[i]); - printf("PmA[%d] is %12.9f\n", i, PmA[i]); - printf("pSPARC->Pm_NPT_NP[%d] in 1st half step is %12.9f\n", i, pSPARC->Pm_NPT_NP[i]); - } - #endif - } - } - // update momentum/mass of particles (reminder: not velocity!) in a step - int ityp, atm; - int count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] = pSPARC->ion_vel[count * 3] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3 + 2]; - // for now they are not velocity! - count ++; - } - } -} - -/* - @ brief: update momentum of thermostat and barostat variables in the second half step -*/ -void updateMomentum_SecondHalf(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double PmTmp[3], PmNew[3]; - int i; - for (i = 0; i < 3; i++){ - PmTmp[i] = pSPARC->Pm_NPT_NP[i]; - } - // update momentum of barostat variables in the second half time step - int judge = 0; - int timeIter = 0; - double G1[3], Gatmp1[3], Gatmp2[3], Gatmp3[3], PmAtmp[3]; - double KbaroTmp = 0; - - double diagElecStress[3], innerControlStress[3]; - diagElecStress[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; - diagElecStress[1] = pSPARC->stress[3] - pSPARC->stress_i[3]; - diagElecStress[2] = pSPARC->stress[5] - pSPARC->stress_i[5]; - // innerControlStress is used for adding confinements on the scale of lattice vectors, such as |a|=|b|. - innerControlStress[0] = diagElecStress[0]; - innerControlStress[1] = diagElecStress[1]; - innerControlStress[2] = diagElecStress[2]; - if (pSPARC->NPTconstraintFlag == 1) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[1]) / 2; - innerControlStress[1] = innerControlStress[0]; - } else if (pSPARC->NPTconstraintFlag == 2) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[2]) / 2; - innerControlStress[2] = innerControlStress[0]; - } else if (pSPARC->NPTconstraintFlag == 3) { - innerControlStress[1] = (diagElecStress[1] + diagElecStress[2]) / 2; - innerControlStress[2] = innerControlStress[1]; - } else if (pSPARC->NPTconstraintFlag == 4) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[1] + diagElecStress[2]) / 3; - innerControlStress[1] = innerControlStress[0]; - innerControlStress[2] = innerControlStress[0]; - } - - while (judge == 0) { - timeIter++; - KbaroTmp = 0; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - G1[i] = 1 / (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) * PmTmp[i] * pSPARC->G_NPT_NP[i]; - KbaroTmp += (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) / 2 * pow(G1[i],2.0); - } - } - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - Gatmp1[i] = innerControlStress[i] * pSPARC->volumeCell / 2.0 / pSPARC->G_NPT_NP[i]; - Gatmp2[i] = G1[i] * PmTmp[i]; - Gatmp3[i] = (pSPARC->prtarget * pSPARC->volumeCell / 2.0 - KbaroTmp) / pSPARC->G_NPT_NP[i]; - PmAtmp[i] = Gatmp1[i] + Gatmp2[i] + Gatmp3[i]; - PmNew[i] = pSPARC->Pm_NPT_NP[i] - pSPARC->MD_dt / 2.0 * pSPARC->S_NPT_NP * PmAtmp[i]; - } - } - judge = 1; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - if (fabs(PmNew[i] - PmTmp[i]) > 1e-7){ - judge = 0; - } - PmTmp[i] = PmNew[i]; - } - } - if (timeIter > pSPARC->maxTimeIter){ - judge = 1; - if (rank == 0) - printf("Reminder: The barostat momentum Pm_NPT_NP does not converge in %d timesteps.\n", pSPARC->maxTimeIter); - } - } - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - pSPARC->Pm_NPT_NP[i] = PmTmp[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_NPT_NP[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_NPT_NP[i]); - #endif - } - } - - // update thermostat velocity in the second half time step - pSPARC->KE = 0.0; - int ityp, atm; - int count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - pSPARC->KE /= pow(pSPARC->S_NPT_NP, 2.0); // from momentum/mass to true velocity - pSPARC->Kbaro = 0.0; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - G1[i] = 1.0 / (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) * PmTmp[i] * pSPARC->G_NPT_NP[i]; - pSPARC->Kbaro += (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) / 2.0 * pow(G1[i],2.0); - } - } - double factor; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - factor = pSPARC->MD_dt / 2.0 * (pSPARC->dof*ktemp*(log(pSPARC->S_NPT_NP) + 1) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP) - pSPARC->NPT_NP_qmass*pSPARC->Sv_NPT_NP; - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor*pSPARC->MD_dt/pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - exit(EXIT_FAILURE); - } - pSPARC->Sv_NPT_NP = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("Sv_NPT_NP in the 2nd half step is %12.9f\n", pSPARC->Sv_NPT_NP); - #endif -} - -/* - @ brief: update positions of particles, value of thermostat variable and barostat variables in the step -*/ -void updatePosition(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - int judge = 0; - // update value of thermostat variable S_NPT_NP - double Stemp = pSPARC->S_NPT_NP; - double Snew; - int timeIter = 0; - while (judge == 0) { - timeIter++; - Snew = pSPARC->S_NPT_NP + pSPARC->MD_dt / 2.0 * (pSPARC->S_NPT_NP + Stemp) * pSPARC->Sv_NPT_NP; - if (fabs(Snew - Stemp) < 1e-7) { - judge = 1; - } - Stemp = Snew; - if (timeIter > pSPARC->maxTimeIter) { - judge = 1; - if (rank == 0) - printf("Reminder: The value of thermostat variable S_NPT_NP does not converge in %d iterations.\n", pSPARC->maxTimeIter); - } - } - #ifdef DEBUG - if (rank == 0) - printf("Stemp is %12.9f\n", Stemp); - #endif - // update values of barostat variables G_NPT_NP - double Gtmp[3], Gnew[3], Gpig[3], GpigOld[3]; - int i; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - Gtmp[i] = pSPARC->G_NPT_NP[i]; - GpigOld[i] = pow(pSPARC->G_NPT_NP[i], 2.0) * pSPARC->Pm_NPT_NP[i]; - } - } - judge = 0; timeIter = 0; - while (judge == 0){ - timeIter++; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - Gpig[i] = pow(Gtmp[i], 2.0) * pSPARC->Pm_NPT_NP[i]; - Gnew[i] = pSPARC->G_NPT_NP[i] + pSPARC->MD_dt / 2.0 * (pSPARC->S_NPT_NP/(pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0))*GpigOld[i] + Stemp/(pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0))*Gpig[i]); - } - } - judge = 1; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - if (fabs(Gnew[i] - Gtmp[i]) > 1e-7) { - judge = 0; - } - Gtmp[i] = Gnew[i]; - } - } - if (timeIter > pSPARC->maxTimeIter) { - judge = 1; - if (rank == 0) - printf("Reminder: The barostat variables G_NPT_NP do not converge in %d iterations.\n", pSPARC->maxTimeIter); - } - } - double G3[3]; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - pSPARC->G_NPT_NP[i] = Gtmp[i]; - G3[i] = pow(Gtmp[i], 2.0) * pSPARC->Pm_NPT_NP[i]; - } - } - #ifdef DEBUG - if (rank == 0) { - printf("pSPARC->G_NPT_NP[0] is %12.9f\n", pSPARC->G_NPT_NP[0]); - printf("pSPARC->G_NPT_NP[1] is %12.9f\n", pSPARC->G_NPT_NP[1]); - printf("pSPARC->G_NPT_NP[2] is %12.9f\n", pSPARC->G_NPT_NP[2]); - } - #endif - // update side lengths of cells and velocities of them - double scalex = sqrt(pSPARC->G_NPT_NP[0]) / pSPARC->range_x; - pSPARC->range_x = sqrt(pSPARC->G_NPT_NP[0]); - double scaley = sqrt(pSPARC->G_NPT_NP[1]) / pSPARC->range_y; - pSPARC->range_y = sqrt(pSPARC->G_NPT_NP[1]); - double scalez = sqrt(pSPARC->G_NPT_NP[2]) / pSPARC->range_z; - pSPARC->range_z = sqrt(pSPARC->G_NPT_NP[2]); - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - if (pSPARC->NPTscaleVecs[0] == 1) - pSPARC->range_x_velo = G3[0] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_x; - else - pSPARC->range_x_velo = 0.0; - if (pSPARC->NPTscaleVecs[1] == 1) - pSPARC->range_y_velo = G3[1] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_y; - else - pSPARC->range_y_velo = 0.0; - if (pSPARC->NPTscaleVecs[2] == 1) - pSPARC->range_z_velo = G3[2] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_z; - else - pSPARC->range_z_velo = 0.0; - // update positions of particles, and restore the values of particle velocities - int count = 0; - int atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = (pSPARC->atom_pos[count * 3]) * scalex + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3]/Stemp); // - pSPARC->atom_pos[count * 3 + 1] = (pSPARC->atom_pos[count * 3 + 1]) * scaley + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 1]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 1]/Stemp); // - pSPARC->atom_pos[count * 3 + 2] = (pSPARC->atom_pos[count * 3 + 2]) * scalez + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 2]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 2]/Stemp); // - pSPARC->ion_vel[count * 3] /= Stemp; - pSPARC->ion_vel[count * 3 + 1] /= Stemp; - pSPARC->ion_vel[count * 3 + 2] /= Stemp; - count ++; - } - pSPARC->S_NPT_NP = Stemp; -} - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); - else - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the qunatities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE/pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - // Compute Ionic stress/pressure - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(sizeof(double), 9); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":NPT_NP_Sv: %.15g\n", pSPARC->Sv_NPT_NP); // velocity of virtual thermal parameter - fprintf(mdout,":NPT_NP_Pm: %.15g %.15g %.15g\n", pSPARC->Pm_NPT_NP[0], pSPARC->Pm_NPT_NP[1], pSPARC->Pm_NPT_NP[2]); // velocity of virtual baro parameter - fprintf(mdout,":NPT_NP_S: %.15g\n", pSPARC->S_NPT_NP); // value of virtual thermal parameter - fprintf(mdout,":NPT_NP_range_x_velo: %.15g\n", pSPARC->range_x_velo); // velocity of virtual x baro parameter - fprintf(mdout,":NPT_NP_range_y_velo: %.15g\n", pSPARC->range_y_velo); // velocity of virtual y baro parameter - fprintf(mdout,":NPT_NP_range_z_velo: %.15g\n", pSPARC->range_z_velo); // velocity of virtual z baro parameter - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_Sv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->Sv_NPT_NP); - else if (strcmpi(str,":NPT_NP_S:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->S_NPT_NP); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":NPT_NP_range_x_velo:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->range_x_velo); - else if (strcmpi(str,":NPT_NP_range_y_velo:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->range_y_velo); - else if (strcmpi(str,":NPT_NP_range_z_velo:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->range_z_velo); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_T i); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->Sv_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->S_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->Sv_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->S_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - \ No newline at end of file From e61601f03c49c6f8abc4506a29554af910217ea4 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:13:29 -0400 Subject: [PATCH 71/87] Delete src/MD_working_nice_but_hamiltonian_timings_issue.c --- ...rking_nice_but_hamiltonian_timings_issue.c | 3558 ----------------- 1 file changed, 3558 deletions(-) delete mode 100644 src/MD_working_nice_but_hamiltonian_timings_issue.c diff --git a/src/MD_working_nice_but_hamiltonian_timings_issue.c b/src/MD_working_nice_but_hamiltonian_timings_issue.c deleted file mode 100644 index 719b7325..00000000 --- a/src/MD_working_nice_but_hamiltonian_timings_issue.c +++ /dev/null @@ -1,3558 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include -#include -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - NPT_NP(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPH(pSPARC); - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers - } -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 100; - - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - - if (rank == 0) { - // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); - - if (pSPARC->fp_energy == NULL) { - fprintf(stderr, "Error: Could not open energy log file!\n"); - exit(EXIT_FAILURE); - } - - // Optional: Print a header to make the file readable in Excel/Python - fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", - "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); - fflush(pSPARC->fp_energy); - } - - fetch_MD_cell_ingredients(pSPARC, false); - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble\n"); - } - } - - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - fetch_MD_cell_ingredients(pSPARC, false); - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPH")){ - pSPARC->NPT_NP_qmass = 0; - } - - Calculate_ionic_stress(pSPARC); - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -*/ -void NPT_NP(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant -This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPH(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - - pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; - pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; - pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; - - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); - - if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); - pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); - pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); - - //Update cell volume - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - - } - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate the velocity of cell lattice vectors - else { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - else { - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - } - - temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - int count = 0; - - pSPARC->KE = 0.0; - int ityp, atm; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); - count ++; - } - } - - pSPARC->KE = pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); - pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); - -} - - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 - } - - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - free(ion_vel_fractional); - - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - - double total_internal_stress[9]; - for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); - -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else { - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[0]; - double baro_const3 = 1.0 / baro_const1; - double ktemp; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // Calculating kinetic energy of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - double sumAllHamilTerms; - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - - - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp; - int count; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else{ - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const3 = 1.0 / baro_const1; - - - - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - - - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - ktemp = pSPARC->kB * pSPARC->thermos_T; - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; - pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - - /*pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - */ - } - - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; - - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) - for (int i = 0; i < 9; i++){ - temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 - } - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - else { - if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - - - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - - double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); - } - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], // snose(1) in Fortran is s - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure);; - } - } - - } - #endif - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); - - //Now impose the constraints on it - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints - // SPARC code was doing both these steps, reference code does not seem to do - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - ktemp = pSPARC->kB * pSPARC->thermos_T; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - /*if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - exit(EXIT_FAILURE); - }*/ - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp - S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - printf("%15.7f \n", S_new); - printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - - //pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); - - - //Before updating cell parameters, compute atom positions in fractional coordinates - double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); - count++; - } - - pSPARC->Snew = S_temp; - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - - //Update the Kinetic energy of the barostat based on new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / pSPARC->volumeCell / pSPARC->volumeCell; //Kinetic - - //Update the Potential energy of the barostat based on new metric tensor - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - - - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); - count++; - } - free(atom_pos_fractional); - - //Update atomic positions and restore ionic velocities - count = 0; - for(int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // - pSPARC->ion_vel[count * 3] /= S_temp; - pSPARC->ion_vel[count * 3 + 1] /= S_temp; - pSPARC->ion_vel[count * 3 + 2] /= S_temp; - count ++; - } - - //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; - } - - // Update SNOSE[0] to S_new - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_temp; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - - -} - - - - -void compute_constraint_stress(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - else{ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - else { - if (pSPARC->NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - } - else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); - } - - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPTconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - else { - if (pSPARC->NPH_ANGLES == 0){ - if (pSPARC->NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; i < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } - - #ifdef DEBUG - if (rank == 0) { - for (int i = 0; i < 9; i++){ - printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); - } - } - #endif - -} - - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const0, baro_const3, baro_const5; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - else{ - baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, - temp_Pm_metric_tensor, 3, - pSPARC->metric_tensor, 3, - 0.0, temp_mat_1, 3); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, - temp_mat_1, 3, - temp_Pm_metric_tensor, 3, - 0.0, temp_mat_2, 3); - - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int ic1 = 0; ic1 < 9; ic1++){ - if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); - #endif - } -} - - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); - } - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } else { - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); - else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":ANGLES:\n"); - fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL:\n"); - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: \n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the quantities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE/pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - // Compute Ionic stress/pressure - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(9, sizeof(double)); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - printf("\n"); - printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - // Print extended system parameters in case of NPH - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); - } - // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - \ No newline at end of file From 1a51b7f44e4f5fcdc775b0ed7d187ef09dc91549 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:13:40 -0400 Subject: [PATCH 72/87] Delete src/md_check.c --- src/md_check.c | 3513 ------------------------------------------------ 1 file changed, 3513 deletions(-) delete mode 100644 src/md_check.c diff --git a/src/md_check.c b/src/md_check.c deleted file mode 100644 index ff738173..00000000 --- a/src/md_check.c +++ /dev/null @@ -1,3513 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include -#include -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - NPT_NP(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPH(pSPARC); - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers - } -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 100; - - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - - if (rank == 0) { - // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies.log", "w"); - - if (pSPARC->fp_energy == NULL) { - fprintf(stderr, "Error: Could not open energy log file!\n"); - exit(EXIT_FAILURE); - } - - // Optional: Print a header to make the file readable in Excel/Python - fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", - "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); - fflush(pSPARC->fp_energy); - } - - fetch_MD_cell_ingredients(pSPARC, false); - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble\n"); - } - } - - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - fetch_MD_cell_ingredients(pSPARC, false); - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPH")){ - pSPARC->NPT_NP_qmass = 0; - } - - Calculate_ionic_stress(pSPARC); - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -*/ -void NPT_NP(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant -This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPH(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - - pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; - pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; - pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; - - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); - - if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt(pSPARC->metric_tensor[0]); - pSPARC->range_y = sqrt(pSPARC->metric_tensor[4]); - pSPARC->range_z = sqrt(pSPARC->metric_tensor[8]); - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); - - //Update cell volume - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - - } - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate the velocity of cell lattice vectors - else { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - else { - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - } - - temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - int count = 0; - - pSPARC->KE = 0.0; - int ityp, atm; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); - count ++; - } - } - pSPARC->KE = pSPARC->KE / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]); - pSPARC->temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); - -} - - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 - } - - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - free(ion_vel_fractional); - - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - - double total_internal_stress[9]; - for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); - -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else { - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - double ktemp; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // Calculating kinetic energy of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - double sumAllHamilTerms; - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - } - } - #endif - - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp; - int count; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else{ - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - - - - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - - - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - ktemp = pSPARC->kB * pSPARC->thermos_T; - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; - pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - - /*pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - */ - } - - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]-pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3]-pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5]-pSPARC->stress_i[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]-pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1]-pSPARC->stress_i[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]-pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4]-pSPARC->stress_i[4]; - - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) - for (int i = 0; i < 9; i++){ - temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = (internal_stress_fractional[i]) + (temp_mat_b[i]); - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - else { - if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - - - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); - - //Now impose the constraints on it - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints - // SPARC code was doing both these steps, reference code does not seem to do - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - ktemp = pSPARC->kB * pSPARC->thermos_T; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - /*if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - exit(EXIT_FAILURE); - }*/ - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp - S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - printf("%15.7f \n", S_new); - printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - - //pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); - - - //Before updating cell parameters, compute atom positions in fractional coordinates - double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); - count++; - } - - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - - //Update the Kinetic energy of the barostat based on new cell volume - //pSPARC->Kbaro = pSPARC->Kbaro / pSPARC->volumeCell / pSPARC->volumeCell; //Kinetic - - //Update the Potential energy of the barostat based on new metric tensor - //pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - - - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); - count++; - } - free(atom_pos_fractional); - - //Update atomic positions and restore ionic velocities - count = 0; - for(int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_new ); // - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_new ); // - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_new ); // - pSPARC->ion_vel[count * 3] /= S_new; - pSPARC->ion_vel[count * 3 + 1] /= S_new; - pSPARC->ion_vel[count * 3 + 2] /= S_new; - count ++; - } - - //Update kinetic energy and kinetic stress based on new S - //pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; - - /*for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; - }*/ - - // Update SNOSE[0] to S_new - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_new; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - - -} - - - - -void compute_constraint_stress(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - else{ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - else { - if (pSPARC->NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - } - else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); - } - - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPTconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - else { - if (pSPARC->NPH_ANGLES == 0){ - if (pSPARC->NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; i < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } - - #ifdef DEBUG - if (rank == 0) { - for (int i = 0; i < 9; i++){ - printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); - } - } - #endif - -} - - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const0, baro_const3, baro_const5; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - else{ - baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, - temp_Pm_metric_tensor, 3, - pSPARC->metric_tensor, 3, - 0.0, temp_mat_1, 3); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, - temp_mat_1, 3, - temp_Pm_metric_tensor, 3, - 0.0, temp_mat_2, 3); - - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder: The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); - #endif - } -} - - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); - } - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } else { - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); - else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":ANGLES:\n"); - fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL:\n"); - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: \n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the quantities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE/pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - // Compute Ionic stress/pressure - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(9, sizeof(double)); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - printf("\n"); - printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - // Print extended system parameters in case of NPH - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); - } - // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - \ No newline at end of file From f0ac6b0413397e99161424d2ecf64aa03e7a9f03 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:13:47 -0400 Subject: [PATCH 73/87] Delete src/md_fortran.c --- src/md_fortran.c | 3591 ---------------------------------------------- 1 file changed, 3591 deletions(-) delete mode 100644 src/md_fortran.c diff --git a/src/md_fortran.c b/src/md_fortran.c deleted file mode 100644 index 5d722f9d..00000000 --- a/src/md_fortran.c +++ /dev/null @@ -1,3591 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include -#include -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - NPT_NP(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPH(pSPARC); - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers - } -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 100; - - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - - if (rank == 0) { - // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies.log", "w"); - - if (pSPARC->fp_energy == NULL) { - fprintf(stderr, "Error: Could not open energy log file!\n"); - exit(EXIT_FAILURE); - } - - // Optional: Print a header to make the file readable in Excel/Python - fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", - "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); - fflush(pSPARC->fp_energy); - } - - fetch_MD_cell_ingredients(pSPARC, false); - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble\n"); - } - } - - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - fetch_MD_cell_ingredients(pSPARC, false); - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPH")){ - pSPARC->NPT_NP_qmass = 0; - } - - Calculate_ionic_stress(pSPARC); - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -*/ -void NPT_NP(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant -This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPH(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - - pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; - pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; - pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; - - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); - - if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt(pSPARC->metric_tensor[0]); - pSPARC->range_y = sqrt(pSPARC->metric_tensor[4]); - pSPARC->range_z = sqrt(pSPARC->metric_tensor[8]); - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); - - //Update cell volume - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - - } - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate the velocity of cell lattice vectors - else { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - else { - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - } - - temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - int count = 0; - - pSPARC->KE = 0.0; - int ityp, atm; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); - count ++; - } - } - pSPARC->KE = pSPARC->KE / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]); - pSPARC->temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); - -} - - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 - } - - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - free(ion_vel_fractional); - - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - - double total_internal_stress[9]; - for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); - -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else { - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - double ktemp; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // Calculating kinetic energy of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b,1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp; - int count; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else{ - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - - - double sumAllHamilTerms; - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - } - } - #endif - } - - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - ktemp = pSPARC->kB * pSPARC->thermos_T; - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; - pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - } - - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; - - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) - for (int i = 0; i < 9; i++){ - temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - - - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 - } - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - } - - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - else { - if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - //Now write Intenal pressure, external pressure to a file - - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - // Calculate/Update the Hamiltonian (constant of motion) - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - //Optionall write all individual energy contributions to the Hamiltonian to an output file - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("AT THE END OF FIRST HALF\n"); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); - } - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], // snose(1) in Fortran is s - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure);; - } - } - - } - #endif - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); - - //Now impose the constraints on it - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - - //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints - // SPARC code was doing both these steps, reference code does not seem to do - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - ktemp = pSPARC->kB * pSPARC->thermos_T; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - /*if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - exit(EXIT_FAILURE); - }*/ - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp - S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - printf("%15.7f \n", S_new); - printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - - pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); - - - //Before updating cell parameters, compute atom positions in fractional coordinates - double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); - count++; - } - - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - - //Update the Kinetic energy of the barostat based on new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / pSPARC->volumeCell / pSPARC->volumeCell; //Kinetic - - //Update the Potential energy of the barostat based on new metric tensor - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - - - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); - count++; - } - free(atom_pos_fractional); - - //Update atomic positions and restore ionic velocities - count = 0; - for(int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_new ); // - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_new ); // - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_new ); // - pSPARC->ion_vel[count * 3] /= pSPARC->SNOSE[0]; - pSPARC->ion_vel[count * 3 + 1] /= pSPARC->SNOSE[0]; - pSPARC->ion_vel[count * 3 + 2] /= pSPARC->SNOSE[0]; - count ++; - } - - //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; - } - - // Update SNOSE[0] to S_new - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_new; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - - -} - - - - -void compute_constraint_stress(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - else{ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - else { - if (pSPARC->NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - } - else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); - } - - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPTconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - else { - if (pSPARC->NPH_ANGLES == 0){ - if (pSPARC->NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; i < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } - - #ifdef DEBUG - if (rank == 0) { - for (int i = 0; i < 9; i++){ - printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); - } - } - #endif - -} - - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const0, baro_const3, baro_const5; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - else{ - baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, - temp_Pm_metric_tensor, 3, - pSPARC->metric_tensor, 3, - 0.0, temp_mat_1, 3); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, - temp_mat_1, 3, - temp_Pm_metric_tensor, 3, - 0.0, temp_mat_2, 3); - - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int ic1 = 0; ic1 < 9; ic1++){ - if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); - #endif - } -} - - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); - } - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } else { - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); - else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":ANGLES:\n"); - fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL:\n"); - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: \n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the quantities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE/pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - // Compute Ionic stress/pressure - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(9, sizeof(double)); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - printf("\n"); - printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - // Print extended system parameters in case of NPH - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); - } - // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - \ No newline at end of file From 89d294338131273001bcbb493bc374266710a5ed Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:13:54 -0400 Subject: [PATCH 74/87] Delete src/md_fortran2.c --- src/md_fortran2.c | 3792 --------------------------------------------- 1 file changed, 3792 deletions(-) delete mode 100644 src/md_fortran2.c diff --git a/src/md_fortran2.c b/src/md_fortran2.c deleted file mode 100644 index 9ab26976..00000000 --- a/src/md_fortran2.c +++ /dev/null @@ -1,3792 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include -#include -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - pSPARC->internal_pressure = 0; - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - NPT_NP(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPH(pSPARC); - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers - } -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 100; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); - printf("herere"); - exit(EXIT_FAILURE); - } - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - if(pSPARC->NPH_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); - printf("he1"); - exit(EXIT_FAILURE); - } - } - } - - if (rank == 0) { - // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); - - if (pSPARC->fp_energy == NULL) { - fprintf(stderr, "Error: Could not open energy log file!\n"); - exit(EXIT_FAILURE); - } - - // Optional: Print a header to make the file readable in Excel/Python - fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", - "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); - fflush(pSPARC->fp_energy); - } - pSPARC->KE_save = 0.0; - fetch_MD_cell_ingredients(pSPARC, false); - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble\n"); - } - } - - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - fetch_MD_cell_ingredients(pSPARC, false); - pSPARC->Pm_ion = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->Pm_ion == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPH")){ - pSPARC->NPT_NP_qmass = 0; - } - - Calculate_ionic_stress(pSPARC); - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -*/ -void NPT_NP(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant -This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPH(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - -void Cart2nonCart_transformMat_MD(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - int i, j, k; - - double TEMP_TOL = 1e-12; - // Construct LatUVec; - double mag; - for(i = 0; i < 3; i++){ - mag = sqrt(pow(pSPARC->full_lattice[3 * i], 2.0) - + pow(pSPARC->full_lattice[3 * i + 1], 2.0) - + pow(pSPARC->full_lattice[3 * i + 2], 2.0)); - pSPARC->LatUVec[3 * i] = pSPARC->full_lattice[3 * i]/mag; - pSPARC->LatUVec[3 * i + 1] = pSPARC->full_lattice[3 * i + 1]/mag; - pSPARC->LatUVec[3 * i + 2] = pSPARC->full_lattice[3 * i + 2]/mag; - } - - // determinant of 3x3 Jacobian - pSPARC->Jacbdet = 0.0; - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - if(i != j && j != k && k != i) - pSPARC->Jacbdet += ((i - j) * (j - k) * (k - i)/2) * pSPARC->LatUVec[3 * i] * pSPARC->LatUVec[3 * j + 1] * pSPARC->LatUVec[3 * k + 2]; - } - } - } - - if(pSPARC->Jacbdet <= 0){ - if(rank == 0) - printf("ERROR: Volume(det(jacobian)) %lf is <= 0\n", pSPARC->Jacbdet); - exit(EXIT_FAILURE); - } - - // transformation matrix for distance - for(i = 0; i < 9; i++) - pSPARC->metricT[i] = 0.0; - - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - pSPARC->metricT[3*i + j] += pSPARC->LatUVec[3*i + k] * pSPARC->LatUVec[3*j + k]; - } - } - } - - pSPARC->metricT[1] = 2 * pSPARC->metricT[1]; - pSPARC->metricT[2] = 2 * pSPARC->metricT[2]; - pSPARC->metricT[5] = 2 * pSPARC->metricT[5]; - - // transformation matrix for gradient - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - pSPARC->gradT[3*j + i] = (pSPARC->LatUVec[3 * ((j+1) % 3) + (i+1) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+2) % 3] - pSPARC->LatUVec[3 * ((j+1) % 3) + (i+2) % 3] * pSPARC->LatUVec[3 * ((j+2) % 3) + (i+1) % 3])/pSPARC->Jacbdet; - } - } - - // transformation matrix for laplacian - for(i = 0; i < 9; i++) - pSPARC->lapcT[i] = 0.0; - - for(i = 0; i < 3; i++){ - for(j = 0; j < 3; j++){ - for(k = 0; k < 3; k++){ - pSPARC->lapcT[3*i + j] += pSPARC->gradT[3*i + k] * pSPARC->gradT[3*j + k]; - } - } - } - - /* Different cell types for laplacian */ - if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 11; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 12; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 13; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) < TEMP_TOL) - pSPARC->cell_typ = 14; - else if(fabs(pSPARC->lapcT[1]) < TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 15; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) < TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 16; - else if(fabs(pSPARC->lapcT[1]) > TEMP_TOL && fabs(pSPARC->lapcT[2]) > TEMP_TOL && fabs(pSPARC->lapcT[5]) > TEMP_TOL) - pSPARC->cell_typ = 17; -#ifdef DEBUG - if(!rank) - printf("\n\nCELL_TYP: %d\n\n",pSPARC->cell_typ); -#endif - /* transform the coefficiens of lapacian*/ - // int p, FDn = pSPARC->order/2; - // double dx_inv, dy_inv, dz_inv, dx2_inv, dy2_inv, dz2_inv; - // dx_inv = 1.0 / (pSPARC->delta_x); - // dy_inv = 1.0 / (pSPARC->delta_y); - // dz_inv = 1.0 / (pSPARC->delta_z); - // dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - // dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - // dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - // for (p = 0; p < FDn + 1; p++) { - // pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - // pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - // pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - // pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - // pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - // pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - // pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - // pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - // pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - // pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - // pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - // pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - // } - // TODO: Find maximum eigenvalue of Hamiltionian (= max. eigvalue of -0.5 lap) for non orthogonal periodic systems -} - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ // Update_cell == false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Cosine of Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - - pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; - pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; - pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; - - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); - - if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); - pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); - pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat_MD(pSPARC); - - double det_metric_tensor = pSPARC->metric_tensor[0] * ( pSPARC->metric_tensor[4] * pSPARC->metric_tensor[8] - pSPARC->metric_tensor[7] * pSPARC->metric_tensor[5] ) - + pSPARC->metric_tensor[1] * ( pSPARC->metric_tensor[5] * pSPARC->metric_tensor[6] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[8] ) - + pSPARC->metric_tensor[2] * ( pSPARC->metric_tensor[3] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[6] * pSPARC->metric_tensor[4] ) ; - - double volume_check = sqrt(det_metric_tensor); - //Update cell volume - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - if (rank ==0){ - printf("Volume from Jac %.6f for MD count %d \n",pSPARC->volumeCell, pSPARC->MDCount); - printf("Volume from metric tensor %.6f for MD count %d \n",volume_check, pSPARC->MDCount); - printf("Jacobian: %.6f for MD count %d \n",pSPARC->Jacbdet, pSPARC->MDCount); - printf(":LatUVec: \n"); - printf(" %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - - } - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - /*double temp_mat11[9]; - for (int i = 0; i < 9; i++){ - temp_mat11[i] = pSPARC->rotation_matrix[i]; - } - - pSPARC->rotation_matrix[1] = temp_mat11[3]; pSPARC->rotation_matrix[2] = temp_mat11[6]; pSPARC->rotation_matrix[5] = temp_mat11[7]; - pSPARC->rotation_matrix[3] = temp_mat11[1]; pSPARC->rotation_matrix[6] = temp_mat11[2]; pSPARC->rotation_matrix[7] = temp_mat11[5]; - */ - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate the velocity of cell lattice vectors - else { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - else { - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - } - - temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double vector[3]={0.0}; - pSPARC->KE = 0.0; - - int count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, &pSPARC->Pm_ion[count*3], 1, 0.0, vector, 1); - pSPARC->KE += cblas_ddot(3, vector, 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - count++; - } - } - - pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); - pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); - -} - - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional, double *ion_vel_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - - double total_internal_stress[9]; - for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); - -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else { - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // Calculating kinetic energy of ions - - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); - - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, pSPARC->Mass[ityp], pSPARC->metric_tensor, 3, &ion_vel_fractional[count * 3], 1, 0.0, &pSPARC->Pm_ion[count * 3], 1); - count++; - } - } - free(ion_vel_fractional); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - pSPARC->KE_save = pSPARC->KE; - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - - - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - - double sumAllHamilTerms; - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - - - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp = pSPARC->kB * pSPARC->thermos_T; - int count; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else{ - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const3 = 1.0 / baro_const1; - - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - - //Calculate_Ionic_particles_Kinetic_energy(pSPARC); - pSPARC->KE = pSPARC->KE_save; - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) ; - pSPARC->SNOSE[1] += 0.5 * Sa * pSPARC->MD_dt / pSPARC->NPT_NP_qmass; - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - } - - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3] - pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5] - pSPARC->stress_i[5]; - internal_stress_cartesian[1] = pSPARC->stress[1] - pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1] - pSPARC->stress_i[1]; - internal_stress_cartesian[5] = pSPARC->stress[4] - pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2] - pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4] - pSPARC->stress_i[4]; - - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) - for (int i = 0; i < 9; i++){ - temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b, 3); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 - } - - double *D2 = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - D2[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - D2[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - D2[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - count++; - } - } - - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, D2); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - free(D2); - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - else { - if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - - double *D2C = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - D2C[count*3] = cblas_ddot(3, &pSPARC->full_lattice[0], 1, &pSPARC->forces[count*3], 1); - D2C[count*3 + 1] = cblas_ddot(3, &pSPARC->full_lattice[3], 1, &pSPARC->forces[count*3], 1); - D2C[count*3 + 2] = cblas_ddot(3, &pSPARC->full_lattice[6], 1, &pSPARC->forces[count*3], 1); - count++; - } - } - - // Eqn. 18i: momentum += 0.5 * dt * S * D2C - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], D2C, 1, pSPARC->Pm_ion, 1); - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - - double *D2 = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); - - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - D2[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - D2[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - D2[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - count++; - } - } - - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, D2); - free(D2); - - //Update Hamiltonian - double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - // pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms ; - // } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - // if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - // pSPARC->init_Hamil_NPH = sumAllHamilTerms ; - // } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); - } - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], // snose(1) in Fortran is s - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure);; - } - } - - } - #endif - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - cblas_daxpy(3 * pSPARC->n_atom, 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0], D2C, 1, pSPARC->Pm_ion, 1); - free(D2C); - - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - - double *ion_vel_fractional = (double *)calloc(3 * pSPARC->n_atom, sizeof(double)); - - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - ion_vel_fractional[count*3] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[0], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - ion_vel_fractional[count*3 + 1] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[3], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - ion_vel_fractional[count*3 + 2] = cblas_ddot(3, &pSPARC->reciprocal_metric_tensor[6], 1, &pSPARC->Pm_ion[count*3], 1) / pSPARC->Mass[ityp]; - count++; - } - } - - // Calculate internal pressure and kinetic stress - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional, ion_vel_fractional); - - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); - - //Now impose the constraints on it - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - } - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp - S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - printf("%15.7f \n", S_new); - printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - - pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); - - - //Before updating cell parameters, compute atom positions in fractional coordinates - double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - //double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); - //ion_vel_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count * 3 + 2]); - //ion_vel_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count * 3 + 2]); - //ion_vel_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count * 3 + 2]); - - count++; - } - pSPARC->Snew = S_temp; - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - - //Update the Potential energy of the barostat based on new metric tensor - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - //Update the Kinetic energy of the barostat based on new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic - - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = atom_pos_fractional[count * 3] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3] / S_temp ); // - atom_pos_fractional[count * 3 + 1] = atom_pos_fractional[count * 3 + 1] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3 + 1] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3 + 1] / S_temp ); // - atom_pos_fractional[count * 3 + 2] = atom_pos_fractional[count * 3 + 2] + 0.5 * pSPARC->MD_dt * ( ion_vel_fractional[count * 3 + 2] / pSPARC->SNOSE[0] + ion_vel_fractional[count * 3 + 2] / S_temp ); // - count++; - } - - - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); - count++; - } - free(atom_pos_fractional); - free(ion_vel_fractional); - //Update atomic positions and restore ionic velocities - count = 0; - for(int atm = 0; atm < pSPARC->n_atom; atm++){ - //pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // - //pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // - //pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // - pSPARC->ion_vel[count * 3] /= S_temp; - pSPARC->ion_vel[count * 3 + 1] /= S_temp; - pSPARC->ion_vel[count * 3 + 2] /= S_temp; - count ++; - } - - //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); - pSPARC->KE_save = pSPARC->KE; - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); - } - - // Update SNOSE[0] to S_new - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_temp; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - - -} - - - - -void compute_constraint_stress(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - else{ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - else { - if (pSPARC->NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - } - else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); - } - - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPTconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - else { - if (pSPARC->NPH_ANGLES == 0){ - if (pSPARC->NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; i < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } - - #ifdef DEBUG - if (rank == 0) { - for (int i = 0; i < 9; i++){ - printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); - } - } - #endif - -} - - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-12; // tolerance criterion for checking convergence - double baro_const0, baro_const3, baro_const5; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - - } - else{ - baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - - } - - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); - #endif - } -} - - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); - } - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } else { - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); - else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE/pSPARC->n_atom); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":ANGLES:\n"); - fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL:\n"); - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: \n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":PRES_INT: %18.10E\n", pSPARC->mean_internal_pressure * CONST_HA_BOHR3_GPA); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the quantities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - - pSPARC->TE = (pSPARC->PE + pSPARC->KE/pSPARC->n_atom); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - // Compute Ionic stress/pressure - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - - if ((pSPARC->MDCount == 0) && (pSPARC->RestartFlag != 1)) { - pSPARC->mean_internal_pressure = (pSPARC->pres-pSPARC->pres_i); - } - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old, mean_internal_pressure_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - mean_internal_pressure_old = pSPARC->mean_internal_pressure; - pSPARC->mean_internal_pressure = (mean_internal_pressure_old * (Count - 1) + pSPARC->internal_pressure) / Count; - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(9, sizeof(double)); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - printf("\n"); - printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - // Print extended system parameters in case of NPH - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); - } - // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - From 8bdac504eefbf6b038dd8d38fbc3d597d00ab3f2 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:14:03 -0400 Subject: [PATCH 75/87] Delete src/md_working_Cartesian_velocity.c --- src/md_working_Cartesian_velocity.c | 3699 --------------------------- 1 file changed, 3699 deletions(-) delete mode 100644 src/md_working_Cartesian_velocity.c diff --git a/src/md_working_Cartesian_velocity.c b/src/md_working_Cartesian_velocity.c deleted file mode 100644 index 20f6ee8e..00000000 --- a/src/md_working_Cartesian_velocity.c +++ /dev/null @@ -1,3699 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include -#include -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - NPT_NP(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPH(pSPARC); - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers - } -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 100; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); - printf("herere"); - exit(EXIT_FAILURE); - } - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - if(pSPARC->NPH_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); - printf("he1"); - exit(EXIT_FAILURE); - } - } - } - - - - if (rank == 0) { - // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); - - if (pSPARC->fp_energy == NULL) { - fprintf(stderr, "Error: Could not open energy log file!\n"); - exit(EXIT_FAILURE); - } - - // Optional: Print a header to make the file readable in Excel/Python - fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", - "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); - fflush(pSPARC->fp_energy); - } - - fetch_MD_cell_ingredients(pSPARC, false); - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble\n"); - } - } - - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - fetch_MD_cell_ingredients(pSPARC, false); - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPH")){ - pSPARC->NPT_NP_qmass = 0; - } - - Calculate_ionic_stress(pSPARC); - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -*/ -void NPT_NP(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant -This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPH(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - - pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; - pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; - pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; - - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); - - if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); - pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); - pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); - - //Update cell volume - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - - } - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - /*double temp_mat11[9]; - for (int i = 0; i < 9; i++){ - temp_mat11[i] = pSPARC->rotation_matrix[i]; - } - - pSPARC->rotation_matrix[1] = temp_mat11[3]; pSPARC->rotation_matrix[2] = temp_mat11[6]; pSPARC->rotation_matrix[5] = temp_mat11[7]; - pSPARC->rotation_matrix[3] = temp_mat11[1]; pSPARC->rotation_matrix[6] = temp_mat11[2]; pSPARC->rotation_matrix[7] = temp_mat11[5]; - */ - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate the velocity of cell lattice vectors - else { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - else { - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - } - - temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double avgvel[3] = {0.0, 0.0, 0.0}; - double mass_tot = 0.0; - int count, ityp, atm; - - // Compute center-of-mass velocity - count = 0; - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - avgvel[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - avgvel[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - avgvel[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - mass_tot += pSPARC->Mass[ityp]; - count++; - } - } - avgvel[0] /= mass_tot; - avgvel[1] /= mass_tot; - avgvel[2] /= mass_tot; - - double vx, vy, vz; - pSPARC->KE = 0.0; - count = 0; - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - vx = pSPARC->ion_vel[count * 3] - avgvel[0]; - vy = pSPARC->ion_vel[count * 3 + 1] - avgvel[1]; - vz = pSPARC->ion_vel[count * 3 + 2] - avgvel[2]; - pSPARC->KE += pSPARC->Mass[ityp] * (vx*vx + vy*vy + vz*vz); - count++; - } - } - - pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); - //pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); - count ++; - } - } - - pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); -} - - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 - } - - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - free(ion_vel_fractional); - - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - - double total_internal_stress[9]; - for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); - -} - - - -void Calculate_Kinetic_stress_and_total_internal_pressure1(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress1[i] = 0.0; //Initialize kinetic stress to 0 - } - - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress1[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress1[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress1[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress1[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress1[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress1[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - free(ion_vel_fractional); - - pSPARC->kinetic_stress1[3] = pSPARC->kinetic_stress1[1]; - pSPARC->kinetic_stress1[6] = pSPARC->kinetic_stress1[2]; - pSPARC->kinetic_stress1[7] = pSPARC->kinetic_stress1[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress1, 1); - -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else { - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[0]; - double baro_const3 = 1.0 / baro_const1; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // Calculating kinetic energy of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - - - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - - double sumAllHamilTerms; - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - - - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp = pSPARC->kB * pSPARC->thermos_T; - int count; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else{ - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const3 = 1.0 / baro_const1; - - - - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - //Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; - pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - } - - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; - - internal_stress_cartesian[0] = pSPARC->stress[0]-pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3]-pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5]-pSPARC->stress_i[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]-pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1]-pSPARC->stress_i[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]-pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4]-pSPARC->stress_i[4]; - - - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) - for (int i = 0; i < 9; i++){ - temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b, 3); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - for (int i = 0; i < 9; i++){ - internal_stress_fractional[i] += pSPARC->kinetic_stress1[i]; - } - - for (int i = 0; i < 9; i++){ - internal_stress_fractional[i] *= 0.5 ; - } - - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 - } - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - else { - if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - //cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; - count = 0; - for (int ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - int len = 3 * pSPARC->nAtomv[ityp]; - // Copy forces slice into ion_accel - cblas_dcopy(len, pSPARC->forces + count, 1, pSPARC->ion_accel + count, 1); - // Scale by 1/mass - cblas_dscal(len, 1.0 / Mass[ityp], pSPARC->ion_accel + count, 1); - count += len; - } - cblas_daxpy(3 * pSPARC->n_atom, thermo_const0, pSPARC->ion_accel, 1, pSPARC->ion_vel, 1); - - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - //Update Hamiltonian - double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); - } - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], // snose(1) in Fortran is s - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure);; - } - } - - } - #endif - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - - //Update the kinetic energy and kinetic stress of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); - - //Now impose the constraints on it - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - //Calculate_Ionic_particles_Kinetic_energy(pSPARC); - //cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - //temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - //temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - //temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - //pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - } - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp - S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - printf("%15.7f \n", S_new); - printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - - pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); - - - //Before updating cell parameters, compute atom positions in fractional coordinates - double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); - ion_vel_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count * 3 + 2]); - ion_vel_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count * 3 + 2]); - ion_vel_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count * 3 + 2]); - - count++; - } - - pSPARC->Snew = S_temp; - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - - //Update the Potential energy of the barostat based on new metric tensor - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - //Update the Kinetic energy of the barostat based on new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic - - - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); - - count++; - } - free(atom_pos_fractional); - free(ion_vel_fractional); - //Update atomic positions and restore ionic velocities - count = 0; - for(int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // - pSPARC->ion_vel[count * 3] /= S_temp; - pSPARC->ion_vel[count * 3 + 1] /= S_temp; - pSPARC->ion_vel[count * 3 + 2] /= S_temp; - count ++; - } - - //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); - } - - // Update SNOSE[0] to S_new - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_temp; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - - -} - - - - -void compute_constraint_stress(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - else{ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - else { - if (pSPARC->NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - } - else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); - } - - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPTconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - else { - if (pSPARC->NPH_ANGLES == 0){ - if (pSPARC->NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; i < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } - - #ifdef DEBUG - if (rank == 0) { - for (int i = 0; i < 9; i++){ - printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); - } - } - #endif - -} - - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-12; // tolerance criterion for checking convergence - double baro_const0, baro_const3, baro_const5; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - else{ - baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); - #endif - } -} - - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); - } - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } else { - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); - else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":ANGLES:\n"); - fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL:\n"); - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: \n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the quantities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE/pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - // Compute Ionic stress/pressure - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(9, sizeof(double)); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - printf("\n"); - printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - // Print extended system parameters in case of NPH - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); - } - // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - From 7664a4044fdecbcdab6873bc4bc8f607df1b1cb9 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:14:11 -0400 Subject: [PATCH 76/87] Delete src/md_working_Cartesian_velocity.c.c --- src/md_working_Cartesian_velocity.c.c | 3700 ------------------------- 1 file changed, 3700 deletions(-) delete mode 100644 src/md_working_Cartesian_velocity.c.c diff --git a/src/md_working_Cartesian_velocity.c.c b/src/md_working_Cartesian_velocity.c.c deleted file mode 100644 index e71c1114..00000000 --- a/src/md_working_Cartesian_velocity.c.c +++ /dev/null @@ -1,3700 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include -#include -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - NPT_NP(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPH(pSPARC); - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers - } -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 100; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); - printf("herere"); - exit(EXIT_FAILURE); - } - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - if(pSPARC->NPH_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); - printf("he1"); - exit(EXIT_FAILURE); - } - } - } - - - - if (rank == 0) { - // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); - - if (pSPARC->fp_energy == NULL) { - fprintf(stderr, "Error: Could not open energy log file!\n"); - exit(EXIT_FAILURE); - } - - // Optional: Print a header to make the file readable in Excel/Python - fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", - "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); - fflush(pSPARC->fp_energy); - } - - fetch_MD_cell_ingredients(pSPARC, false); - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble\n"); - } - } - - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - fetch_MD_cell_ingredients(pSPARC, false); - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPH")){ - pSPARC->NPT_NP_qmass = 0; - } - - Calculate_ionic_stress(pSPARC); - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -*/ -void NPT_NP(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant -This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPH(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - - pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; - pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; - pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; - - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); - - if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); - pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); - pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); - - //Update cell volume - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - - } - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - /*double temp_mat11[9]; - for (int i = 0; i < 9; i++){ - temp_mat11[i] = pSPARC->rotation_matrix[i]; - } - - pSPARC->rotation_matrix[1] = temp_mat11[3]; pSPARC->rotation_matrix[2] = temp_mat11[6]; pSPARC->rotation_matrix[5] = temp_mat11[7]; - pSPARC->rotation_matrix[3] = temp_mat11[1]; pSPARC->rotation_matrix[6] = temp_mat11[2]; pSPARC->rotation_matrix[7] = temp_mat11[5]; - */ - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate the velocity of cell lattice vectors - else { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - else { - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - } - - temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double avgvel[3] = {0.0, 0.0, 0.0}; - double mass_tot = 0.0; - int count, ityp, atm; - - // Compute center-of-mass velocity - count = 0; - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - avgvel[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - avgvel[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - avgvel[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - mass_tot += pSPARC->Mass[ityp]; - count++; - } - } - avgvel[0] /= mass_tot; - avgvel[1] /= mass_tot; - avgvel[2] /= mass_tot; - - double vx, vy, vz; - pSPARC->KE = 0.0; - count = 0; - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - vx = pSPARC->ion_vel[count * 3] - avgvel[0]; - vy = pSPARC->ion_vel[count * 3 + 1] - avgvel[1]; - vz = pSPARC->ion_vel[count * 3 + 2] - avgvel[2]; - pSPARC->KE += pSPARC->Mass[ityp] * (vx*vx + vy*vy + vz*vz); - count++; - } - } - - pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); - //pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); - count ++; - } - } - - pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); -} - - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 - } - - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - free(ion_vel_fractional); - - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - - double total_internal_stress[9]; - for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); - -} - - - -void Calculate_Kinetic_stress_and_total_internal_pressure1(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress1[i] = 0.0; //Initialize kinetic stress to 0 - } - - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress1[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress1[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress1[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress1[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress1[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress1[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - free(ion_vel_fractional); - - pSPARC->kinetic_stress1[3] = pSPARC->kinetic_stress1[1]; - pSPARC->kinetic_stress1[6] = pSPARC->kinetic_stress1[2]; - pSPARC->kinetic_stress1[7] = pSPARC->kinetic_stress1[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress1, 1); - -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else { - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[0]; - double baro_const3 = 1.0 / baro_const1; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // Calculating kinetic energy of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - - - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - - double sumAllHamilTerms; - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - - - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp = pSPARC->kB * pSPARC->thermos_T; - int count; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else{ - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const3 = 1.0 / baro_const1; - - - - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - //Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; - pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - } - - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; - - internal_stress_cartesian[0] = pSPARC->stress[0]-pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3]-pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5]-pSPARC->stress_i[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]-pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1]-pSPARC->stress_i[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]-pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4]-pSPARC->stress_i[4]; - - - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) - for (int i = 0; i < 9; i++){ - temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b, 3); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - for (int i = 0; i < 9; i++){ - internal_stress_fractional[i] += pSPARC->kinetic_stress1[i]; - } - - for (int i = 0; i < 9; i++){ - internal_stress_fractional[i] *= 0.5 ; - } - - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 - } - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - else { - if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - //cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - //Update Hamiltonian - double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); - } - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], // snose(1) in Fortran is s - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure);; - } - } - - } - #endif - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - - //Update the kinetic energy and kinetic stress of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); - - //Now impose the constraints on it - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - //Calculate_Ionic_particles_Kinetic_energy(pSPARC); - //cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - //temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - //temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - //temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - //pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - } - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp - S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - printf("%15.7f \n", S_new); - printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - - pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); - - - //Before updating cell parameters, compute atom positions in fractional coordinates - double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); - ion_vel_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count * 3 + 2]); - ion_vel_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count * 3 + 2]); - ion_vel_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count * 3 + 2]); - - count++; - } - - pSPARC->Snew = S_temp; - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - - //Update the Potential energy of the barostat based on new metric tensor - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - //Update the Kinetic energy of the barostat based on new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic - - - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); - - count++; - } - free(atom_pos_fractional); - free(ion_vel_fractional); - //Update atomic positions and restore ionic velocities - count = 0; - for(int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // - pSPARC->ion_vel[count * 3] /= S_temp; - pSPARC->ion_vel[count * 3 + 1] /= S_temp; - pSPARC->ion_vel[count * 3 + 2] /= S_temp; - count ++; - } - - //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); - } - - // Update SNOSE[0] to S_new - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_temp; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - - -} - - - - -void compute_constraint_stress(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - else{ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - else { - if (pSPARC->NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - } - else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); - } - - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPTconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - else { - if (pSPARC->NPH_ANGLES == 0){ - if (pSPARC->NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; i < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } - - #ifdef DEBUG - if (rank == 0) { - for (int i = 0; i < 9; i++){ - printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); - } - } - #endif - -} - - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-12; // tolerance criterion for checking convergence - double baro_const0, baro_const3, baro_const5; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - else{ - baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); - #endif - } -} - - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); - } - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } else { - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); - else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":ANGLES:\n"); - fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL:\n"); - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: \n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the quantities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE/pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - // Compute Ionic stress/pressure - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(9, sizeof(double)); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - printf("\n"); - printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - // Print extended system parameters in case of NPH - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); - } - // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - From 841d50203796b91d4e5f4ad02772e679fc755af6 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:14:18 -0400 Subject: [PATCH 77/87] Delete src/md_working_but_velocity_fractional_cartesian_issue.c --- ..._but_velocity_fractional_cartesian_issue.c | 3700 ----------------- 1 file changed, 3700 deletions(-) delete mode 100644 src/md_working_but_velocity_fractional_cartesian_issue.c diff --git a/src/md_working_but_velocity_fractional_cartesian_issue.c b/src/md_working_but_velocity_fractional_cartesian_issue.c deleted file mode 100644 index e71c1114..00000000 --- a/src/md_working_but_velocity_fractional_cartesian_issue.c +++ /dev/null @@ -1,3700 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include -#include -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - NPT_NP(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPH(pSPARC); - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers - } -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 100; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPT_NP. Please input valid amount of mass of baro variable.\n"); - printf("herere"); - exit(EXIT_FAILURE); - } - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - if(pSPARC->NPH_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero in NPH. Please input valid amount of mass of baro variable.\n"); - printf("he1"); - exit(EXIT_FAILURE); - } - } - } - - - - if (rank == 0) { - // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies_Metric_tensor_ok.log", "w"); - - if (pSPARC->fp_energy == NULL) { - fprintf(stderr, "Error: Could not open energy log file!\n"); - exit(EXIT_FAILURE); - } - - // Optional: Print a header to make the file readable in Excel/Python - fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", - "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); - fflush(pSPARC->fp_energy); - } - - fetch_MD_cell_ingredients(pSPARC, false); - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble\n"); - } - } - - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - fetch_MD_cell_ingredients(pSPARC, false); - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPH")){ - pSPARC->NPT_NP_qmass = 0; - } - - Calculate_ionic_stress(pSPARC); - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -*/ -void NPT_NP(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant -This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPH(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - - //Calculate initial hamitonian - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - - pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; - pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; - pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; - - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); - - if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt( pSPARC->metric_tensor[0] ); - pSPARC->range_y = sqrt( pSPARC->metric_tensor[4] ); - pSPARC->range_z = sqrt( pSPARC->metric_tensor[8] ); - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); - - //Update cell volume - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - - } - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - /*double temp_mat11[9]; - for (int i = 0; i < 9; i++){ - temp_mat11[i] = pSPARC->rotation_matrix[i]; - } - - pSPARC->rotation_matrix[1] = temp_mat11[3]; pSPARC->rotation_matrix[2] = temp_mat11[6]; pSPARC->rotation_matrix[5] = temp_mat11[7]; - pSPARC->rotation_matrix[3] = temp_mat11[1]; pSPARC->rotation_matrix[6] = temp_mat11[2]; pSPARC->rotation_matrix[7] = temp_mat11[5]; - */ - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate the velocity of cell lattice vectors - else { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - else { - cblas_dscal(9, pSPARC->Snew / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - } - - temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double avgvel[3] = {0.0, 0.0, 0.0}; - double mass_tot = 0.0; - int count, ityp, atm; - - // Compute center-of-mass velocity - count = 0; - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - avgvel[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - avgvel[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - avgvel[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - mass_tot += pSPARC->Mass[ityp]; - count++; - } - } - avgvel[0] /= mass_tot; - avgvel[1] /= mass_tot; - avgvel[2] /= mass_tot; - - double vx, vy, vz; - pSPARC->KE = 0.0; - count = 0; - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - for (atm = 0; atm < pSPARC->nAtomv[ityp]; atm++) { - vx = pSPARC->ion_vel[count * 3] - avgvel[0]; - vy = pSPARC->ion_vel[count * 3 + 1] - avgvel[1]; - vz = pSPARC->ion_vel[count * 3 + 2] - avgvel[2]; - pSPARC->KE += pSPARC->Mass[ityp] * (vx*vx + vy*vy + vz*vz); - count++; - } - } - - pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); - //pSPARC->temperature = 2.0 * pSPARC->KE / ( pSPARC->dof * pSPARC->kB ); - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); - count ++; - } - } - - pSPARC->KE = 0.5 * pSPARC->KE / ( pSPARC->SNOSE[0] * pSPARC->SNOSE[0] ); -} - - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 - } - - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - free(ion_vel_fractional); - - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - - double total_internal_stress[9]; - for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); - -} - - - -void Calculate_Kinetic_stress_and_total_internal_pressure1(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress1[i] = 0.0; //Initialize kinetic stress to 0 - } - - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress1[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress1[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress1[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress1[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress1[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress1[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - free(ion_vel_fractional); - - pSPARC->kinetic_stress1[3] = pSPARC->kinetic_stress1[1]; - pSPARC->kinetic_stress1[6] = pSPARC->kinetic_stress1[2]; - pSPARC->kinetic_stress1[7] = pSPARC->kinetic_stress1[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress1, 1); - -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else { - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[0]; - double baro_const3 = 1.0 / baro_const1; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // Calculating kinetic energy of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - - - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - - double sumAllHamilTerms; - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - } - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - - - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp = pSPARC->kB * pSPARC->thermos_T; - int count; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else{ - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const3 = 1.0 / baro_const1; - - - - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - //Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; - pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - } - - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; - - internal_stress_cartesian[0] = pSPARC->stress[0]-pSPARC->stress_i[0]; internal_stress_cartesian[4] = pSPARC->stress[3]-pSPARC->stress_i[3]; internal_stress_cartesian[8] = pSPARC->stress[5]-pSPARC->stress_i[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]-pSPARC->stress_i[1]; internal_stress_cartesian[2] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[3] = pSPARC->stress[1]-pSPARC->stress_i[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]-pSPARC->stress_i[4]; internal_stress_cartesian[6] = pSPARC->stress[2]-pSPARC->stress_i[2]; internal_stress_cartesian[7] = pSPARC->stress[4]-pSPARC->stress_i[4]; - - - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) - for (int i = 0; i < 9; i++){ - temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b, 3); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional, 3); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - for (int i = 0; i < 9; i++){ - internal_stress_fractional[i] += pSPARC->kinetic_stress1[i]; - } - - for (int i = 0; i < 9; i++){ - internal_stress_fractional[i] *= 0.5 ; - } - - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 - } - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - else { - if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - //cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - //Update Hamiltonian - double sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); - } - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], // snose(1) in Fortran is s - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure);; - } - } - - } - #endif - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - - //Update the kinetic energy and kinetic stress of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); - - //Now impose the constraints on it - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - //Calculate_Ionic_particles_Kinetic_energy(pSPARC); - //cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - //temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - //temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - //temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - //pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("WARNING: The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - } - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp - S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - printf("%15.7f \n", S_new); - printf("Reminder: The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - - pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_temp); - - - //Before updating cell parameters, compute atom positions in fractional coordinates - double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); - ion_vel_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count * 3 + 2]); - ion_vel_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count * 3 + 2]); - ion_vel_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count * 3 + 2]); - - count++; - } - - pSPARC->Snew = S_temp; - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - - //Update the Potential energy of the barostat based on new metric tensor - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - //Update the Kinetic energy of the barostat based on new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / ( pSPARC->volumeCell * pSPARC->volumeCell ); //Kinetic - - - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3] = ( pSPARC->full_lattice[0] * ion_vel_fractional[count*3] + pSPARC->full_lattice[3] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 1] = ( pSPARC->full_lattice[1] * ion_vel_fractional[count*3] + pSPARC->full_lattice[4] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * ion_vel_fractional[count * 3 + 2]); - pSPARC->ion_vel[count * 3 + 2] = ( pSPARC->full_lattice[2] * ion_vel_fractional[count*3] + pSPARC->full_lattice[5] * ion_vel_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * ion_vel_fractional[count * 3 + 2]); - - count++; - } - free(atom_pos_fractional); - free(ion_vel_fractional); - //Update atomic positions and restore ionic velocities - count = 0; - for(int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_temp ); // - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_temp ); // - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_temp ); // - pSPARC->ion_vel[count * 3] /= S_temp; - pSPARC->ion_vel[count * 3 + 1] /= S_temp; - pSPARC->ion_vel[count * 3 + 2] /= S_temp; - count ++; - } - - //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]) / ( S_temp * S_temp ); - } - - // Update SNOSE[0] to S_new - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_temp; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - - -} - - - - -void compute_constraint_stress(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - else{ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - else { - if (pSPARC->NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - } - else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); - } - - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPTconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - else { - if (pSPARC->NPH_ANGLES == 0){ - if (pSPARC->NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; i < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } - - #ifdef DEBUG - if (rank == 0) { - for (int i = 0; i < 9; i++){ - printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); - } - } - #endif - -} - - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-12; // tolerance criterion for checking convergence - double baro_const0, baro_const3, baro_const5; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - else{ - baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, temp_Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_1, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_1, 3, temp_Pm_metric_tensor, 3, 0.0, temp_mat_2, 3); - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_Pm_metric_tensor[i] - temp_Pm_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); - #endif - } -} - - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); - } - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } else { - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); - else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":ANGLES:\n"); - fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL:\n"); - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: \n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the quantities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE/pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - // Compute Ionic stress/pressure - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(9, sizeof(double)); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - printf("\n"); - printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - // Print extended system parameters in case of NPH - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); - } - // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - From 5ddd1c42386042340ba77bba4a84dfb45a770fdc Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:14:26 -0400 Subject: [PATCH 78/87] Delete src/md_working_on.c --- src/md_working_on.c | 3591 ------------------------------------------- 1 file changed, 3591 deletions(-) delete mode 100644 src/md_working_on.c diff --git a/src/md_working_on.c b/src/md_working_on.c deleted file mode 100644 index 25a438da..00000000 --- a/src/md_working_on.c +++ /dev/null @@ -1,3591 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include -#include -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,"\n\n:MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - NPT_NP(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - NPH(pSPARC); - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); - if (rank == 0 && pSPARC->fp_energy != NULL) { - fclose(pSPARC->fp_energy); - pSPARC->fp_energy = NULL; // Good practice to prevent dangling pointers - } -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0] * pSPARC->LatVec[0] + pSPARC->LatVec[1] * pSPARC->LatVec[1] + pSPARC->LatVec[2] * pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3] * pSPARC->LatVec[3] + pSPARC->LatVec[4] * pSPARC->LatVec[4] + pSPARC->LatVec[5] * pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6] * pSPARC->LatVec[6] + pSPARC->LatVec[7] * pSPARC->LatVec[7] + pSPARC->LatVec[8] * pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 100; - - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - - if (rank == 0) { - // "w" creates a new file; "a" appends to an existing one. - pSPARC->fp_energy = fopen("MD_energies.log", "w"); - - if (pSPARC->fp_energy == NULL) { - fprintf(stderr, "Error: Could not open energy log file!\n"); - exit(EXIT_FAILURE); - } - - // Optional: Print a header to make the file readable in Excel/Python - fprintf(pSPARC->fp_energy, "# %13s %15s %15s %15s %15s %15s %15s %15s %15s %15s %15s\n", - "KE", "Etot", "Barostat", "Thermostat", "Total", "Hamiltonian", "SNOSE[0]", "H0", "VOLUME", "TEMPERATURE", "PRESSURE"); - fflush(pSPARC->fp_energy); - } - - fetch_MD_cell_ingredients(pSPARC, false); - - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable\n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - pSPARC->NPT_NP_qmass = 0; // Internally we are setting NPT_NP_qmass to 0; as rest of the functionality is entirely same as NPT_NP so we are using the same functions for NPH - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble\n"); - } - } - - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - fetch_MD_cell_ingredients(pSPARC, false); - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->pressure_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i = 0; i < 6; i++){ - pSPARC->stress_external[i] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPH")){ - pSPARC->NPT_NP_qmass = 0; - } - - Calculate_ionic_stress(pSPARC); - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -*/ -void NPT_NP(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant -This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPH(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - //Calculate initial hamitonian - NPT_NP_and_NPH_init_hamiltonian(pSPARC); - } - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1){ - //performs matrix1 = matrix1 + transpose(matrix1) - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; -} - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC, bool update_cell){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double old_cell[9]; double new_cell[9]; - - if (update_cell == false){ // Update_cell === false only initializes the cell parameters and basic key ingredients used in NPT_NP and NPH ensemble; such as full_lattice, metric_tensor, reciprocal_metric_tensor ...etc, to be used when doing first step of MD - - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); // cos_gamma - - pSPARC->angle_12 = acos(pSPARC->initialLatVecAngles[2]) * 180 / M_PI; - pSPARC->angle_13 = acos(pSPARC->initialLatVecAngles[1]) * 180 / M_PI; - pSPARC->angle_23 = acos(pSPARC->initialLatVecAngles[0]) * 180 / M_PI; - - } - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3] / sqrt(pSPARC->metric_tensor[0]); - new_cell[4] = sqrt( pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3] / pSPARC->metric_tensor[0]); - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6] / sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = ( pSPARC->metric_tensor[0] * pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3] * pSPARC->metric_tensor[6]) / sqrt(pSPARC->metric_tensor[0] * pSPARC->metric_tensor[0] * pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0] * pSPARC->metric_tensor[3] * pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]); - - if (update_cell == true){ //update_cell == true is used to update the lattice_vectors of full cell, reciprocal metric tensor, reciprocal lattice vectors, cell volume, cell lattice vectors velocities and basically all the parameters that needs to be updated accounting the change in cell lattice vectors lengths and angles; to be used after the first step of MD (and at the end of each MD step). - //Update full cell's lattice vectors - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, new_cell, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->full_lattice, 3); - - //Update range_x, range_y, range_z, volumeCell, - pSPARC->range_x = sqrt(pSPARC->metric_tensor[0]); - pSPARC->range_y = sqrt(pSPARC->metric_tensor[4]); - pSPARC->range_z = sqrt(pSPARC->metric_tensor[8]); - - //Update LatUVec, Jacbdet, metricT, gradT, lapcT - Cart2nonCart_transformMat(pSPARC); - - //Update cell volume - pSPARC->volumeCell = pSPARC->Jacbdet * pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - - // Update/Calculate new angles between lattice vectors (only for inference, not used anywhere in the code) - double cos_gamma_new = pSPARC->metric_tensor[1] / (pSPARC->range_x * pSPARC->range_y); - double cos_beta_new = pSPARC->metric_tensor[2] / (pSPARC->range_x * pSPARC->range_z); - double cos_alpha_new = pSPARC->metric_tensor[5] / (pSPARC->range_y * pSPARC->range_z); - - pSPARC->angle_12 = acos(cos_gamma_new) * 180 / M_PI; - pSPARC->angle_13 = acos(cos_beta_new) * 180 / M_PI; - pSPARC->angle_23 = acos(cos_alpha_new) * 180 / M_PI; - - //Update LATVEC_SCALE and LatVec - if (pSPARC->Flag_latvec_scale == 1){ - // LatVec just accounts for change in orientation/angles - for (int i = 0; i < 3; i++){ - pSPARC->LatVec[i] = pSPARC->LatUVec[i] * pSPARC->initialLatVecLength[0]; - pSPARC->LatVec[i+3] = pSPARC->LatUVec[i+3] * pSPARC->initialLatVecLength[1]; - pSPARC->LatVec[i+6] = pSPARC->LatUVec[i+6] * pSPARC->initialLatVecLength[2]; - } - - // LATVEC_SCALE accounts for change in lengths - pSPARC->latvec_scale_y = pSPARC->range_y / pSPARC->initialLatVecLength[1]; - pSPARC->latvec_scale_x = pSPARC->range_x / pSPARC->initialLatVecLength[0]; - pSPARC->latvec_scale_z = pSPARC->range_z / pSPARC->initialLatVecLength[2]; - - } - - } - //Update reciprocal lattice vectors, reciprocal metric tensor - for (int i = 0; i < 9; i++){ - old_cell[i] = pSPARC->full_lattice[i]; - } - - - - // Calculate the inverse of lattice-vector - double U[9]; double S[3]; double VT[9]; double superb[2]; double temp_mat[9]; - double S_inv[9] = {0}; - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3, 3, old_cell, 3, S, U, 3, VT, 3, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0 / S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since full_lattice is rowMajor, reciprocal_lattice is columnMajor - // i.e. the reciprocal lattice vectors (of full_lattice) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPARC->reciprocal_lattice, 3); - // Now computing reciprocal metric tensor, - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, pSPARC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - if (update_cell == false){ - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - //Initiating cell lattice vectors velocity as zero - for (int i = 0; i < 9; i++){ - pSPARC->lattice_avg_velo[i] = 0.0; - } - } - - //If updating the cell, then also calculate the velocity of cell lattice vectors - else { - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int i = 0; i < 9; i++){ - temp_mat_3[i] = pSPARC->Pm_metric_tensor[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - else { - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - } - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int i = 0; i < 9; i++){ - temp_mat_2[i] = 0.0; - } - - temp_mat_2[0] = 0.5 * temp_mat_3[0] / (new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->rotation_matrix, 3, 0.0, pSPARC->lattice_avg_velo, 3); - } -} - - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - int count = 0; - - pSPARC->KE = 0.0; - int ityp, atm; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]); - count ++; - } - } - pSPARC->KE = pSPARC->KE / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]); - pSPARC->temperature = 2.0 * pSPARC->KE / (pSPARC->dof * pSPARC->kB); - -} - - -void Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC, double *internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double *ion_vel_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] = 0.0; //Initialize kinetic stress to 0 - } - - if (ion_vel_fractional == NULL) { - fprintf(stderr, "Error: Memory allocation failed for momentum array.\n"); - // Handle error (e.g., exit or return) - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - ion_vel_fractional[count*3] = (pSPARC->reciprocal_lattice[0] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[6] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+1] = (pSPARC->reciprocal_lattice[1] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[7] * pSPARC->ion_vel[count*3+2]); - ion_vel_fractional[count*3+2] = (pSPARC->reciprocal_lattice[2] * pSPARC->ion_vel[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->ion_vel[count*3+1] + pSPARC->reciprocal_lattice[8] * pSPARC->ion_vel[count*3+2]); - count++; - } - } - - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->kinetic_stress[0] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3]; - pSPARC->kinetic_stress[1] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[2] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[4] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+1]; - pSPARC->kinetic_stress[5] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+1] * ion_vel_fractional[count*3+2]; - pSPARC->kinetic_stress[8] += pSPARC->Mass[ityp] * ion_vel_fractional[count*3+2] * ion_vel_fractional[count*3+2]; - count++; - } - } - - free(ion_vel_fractional); - - pSPARC->kinetic_stress[3] = pSPARC->kinetic_stress[1]; - pSPARC->kinetic_stress[6] = pSPARC->kinetic_stress[2]; - pSPARC->kinetic_stress[7] = pSPARC->kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), pSPARC->kinetic_stress, 1); - - double total_internal_stress[9]; - for (int i = 0; i < 9; i++){ - total_internal_stress[i] = ( pSPARC->kinetic_stress[i] - internal_stress_fractional[i] - pSPARC->constraint_stress[i] ); - } - - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), total_internal_stress, 1); - - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, total_internal_stress, 1, pSPARC->metric_tensor, 1); - -} - - -void NPT_NP_and_NPH_init_hamiltonian(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else { - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - double ktemp; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10)----------------------------------// - // Calculating kinetic energy of ions - cblas_dscal(pSPARC->n_atom * 3, pSPARC->SNOSE[2], pSPARC->ion_vel, 1); - Calculate_Ionic_particles_Kinetic_energy(pSPARC); //Term 1 in Eqn.10 Hernandez paper - - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic; Term 6 in Eqn.10 Hernandez paper - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(9, baro_const2, pSPARC->Pm_metric_tensor, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b,1);//Kinetic; Term 3 in Eqn.10 in Hernandez paper - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell; //Potential; Term 4 in Eqn.10 in Hernandez paper - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential; Term 5 in Eqn.10 in Hernandez paper - - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10)----------------------------------// -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp; - int count; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - - //Initialize some useful constants - double baro_const1; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - else{ - baro_const1 = pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - } - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - - - double sumAllHamilTerms; - - //------------------------------------------------------------DURING INITIALIZATION-------------------------------------------------------------// - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; //Etot is 2nd term in Eqn. 10 in Hernandez paper - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; //Initial Hamiltonian H0 - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - pSPARC->init_Hamil_NPH = sumAllHamilTerms; //Initial Hamiltonian H0 - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - } - } - #endif - } - - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa = 0.0; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - ktemp = pSPARC->kB * pSPARC->thermos_T; - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; - pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - // Update the kinetic energy of the thermostat - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic; Term 7 in Eqn.10 Hernandez paper - - } - - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress_cartesian[4] = pSPARC->stress[3]; internal_stress_cartesian[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress_cartesian[2] = pSPARC->stress[2]; internal_stress_cartesian[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress_cartesian[6] = pSPARC->stress[2]; internal_stress_cartesian[7] = pSPARC->stress[4]; - - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: reciprocal lattice vectors are columns) - for (int i = 0; i < 9; i++){ - temp_mat_a[i] = pSPARC->reciprocal_lattice[i]; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5 * pSPARC->volumeCell, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); //Multiplying by volume since the stress is stored in the units of Ha/bohr^3 - - - cblas_dscal(3 * pSPARC->n_atom, pSPARC->SNOSE[0], pSPARC->ion_vel, 1); - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = 0.0; //Initialize constraint stress to 0 - } - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); //Calculate kinetic stress with the initial distribution of Ionic particles velocity - } - - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int i = 0; i < 9; i++){ - temp_Pm_mat[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Eqn. 18h Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = (internal_stress_fractional[i] - pSPARC->kinetic_stress[i]) + (temp_mat_b[i]); - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - else { - if (pSPARC->NPH_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - } - - //This block below seems redundant, since we already update the momenta based on constraints in function: compute_constraint_stress - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] + pSPARC->constraint_stress[i] - pSPARC->kinetic_stress[i] + temp_mat_b[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - pSPARC->Pm_metric_tensor[i] = temp_Pm_mat[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9, temp_mat_a, 1, temp_mat_b, 1);//Kinetic - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - - double thermo_const0 = pSPARC->MD_dt * pSPARC->SNOSE[0] / 2.0; - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - //Now write Intenal pressure, external pressure to a file - - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - // Calculate/Update the Hamiltonian (constant of motion) - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); //Eqn. 8 in the Hernandez paper - } - else { - pSPARC->Hamiltonian_NPH = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPH); //Eqn. 8 in the Hernandez paper - } - //Optionall write all individual energy contributions to the Hamiltonian to an output file - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("AT THE END OF FIRST HALF\n"); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure * CONST_HA_BOHR3_GPA); - } - } - else { - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPH); - if (pSPARC->fp_energy != NULL) { - fprintf(pSPARC->fp_energy, "%15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g %15.7g\n", - pSPARC->KE, - pSPARC->Etot, - pSPARC->Kbaro + pSPARC->Ubaro, - pSPARC->Kther + pSPARC->Uther, - sumAllHamilTerms, - pSPARC->Hamiltonian_NPT_NP, - pSPARC->SNOSE[0], // snose(1) in Fortran is s - pSPARC->init_Hamil_NPT_NP, - pSPARC->volumeCell, - pSPARC->temperature, - pSPARC->internal_pressure);; - } - } - - } - #endif - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] += thermo_const0 * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += thermo_const0 * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += thermo_const0 * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC, internal_stress_fractional); - - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC, internal_stress_fractional); - - //Now impose the constraints on it - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - else { - if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - } - - - //At this step I feel we should first impose all the constraints when updating the momenta of barostat, and recalculate the kinetic energy of barostat after imposing these constraints - // SPARC code was doing both these steps, reference code does not seem to do - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - ktemp = pSPARC->kB * pSPARC->thermos_T; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * ( log(pSPARC->SNOSE[0]) + 1 ) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - /*if ((1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - exit(EXIT_FAILURE); - }*/ - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("SNOSE[1] in the 2nd half step is %12.9f\n", pSPARC->SNOSE[1]); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new = 1.0; double S_temp = pSPARC->SNOSE[0]; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT_NP ensemble (skip is running NPH ensemble) - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp - S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - printf("%15.7f \n", S_new); - printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - - pSPARC->Kbaro = pSPARC->Kbaro * pSPARC->volumeCell * pSPARC->volumeCell; - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); - - - //Before updating cell parameters, compute atom positions in fractional coordinates - double *atom_pos_fractional = (double *)malloc(3 * pSPARC->n_atom * sizeof(double)); - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - atom_pos_fractional[count * 3] = ( pSPARC->reciprocal_lattice[0] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[3] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[6] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 1] = ( pSPARC->reciprocal_lattice[1] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[4] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[7] * pSPARC->atom_pos[count * 3 + 2]); - atom_pos_fractional[count * 3 + 2] = ( pSPARC->reciprocal_lattice[2] * pSPARC->atom_pos[count*3] + pSPARC->reciprocal_lattice[5] * pSPARC->atom_pos[count * 3 + 1] + pSPARC->reciprocal_lattice[8] * pSPARC->atom_pos[count * 3 + 2]); - count++; - } - - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC, true); - - //Update the Kinetic energy of the barostat based on new cell volume - pSPARC->Kbaro = pSPARC->Kbaro / pSPARC->volumeCell / pSPARC->volumeCell; //Kinetic - - //Update the Potential energy of the barostat based on new metric tensor - pSPARC->Ubaro = pSPARC->pressure_external * pSPARC->volumeCell + 0.5 * cblas_ddot(9, pSPARC->external_stress_lattice, 1, pSPARC->metric_tensor, 1); //Potential - - - - // Now reconvert atomic positions to cartesian coordinates (remember this are still of previous step, they have yet to be updated) - count = 0; - for (int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = ( pSPARC->full_lattice[0] * atom_pos_fractional[count*3] + pSPARC->full_lattice[3] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[6] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 1] = ( pSPARC->full_lattice[1] * atom_pos_fractional[count*3] + pSPARC->full_lattice[4] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[7] * atom_pos_fractional[count * 3 + 2]); - pSPARC->atom_pos[count * 3 + 2] = ( pSPARC->full_lattice[2] * atom_pos_fractional[count*3] + pSPARC->full_lattice[5] * atom_pos_fractional[count * 3 + 1] + pSPARC->full_lattice[8] * atom_pos_fractional[count * 3 + 2]); - count++; - } - free(atom_pos_fractional); - - //Update atomic positions and restore ionic velocities - count = 0; - for(int atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count*3] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3] / S_new ); // - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 1] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 1] / S_new ); // - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] + pSPARC->MD_dt / 2.0 * ( pSPARC->ion_vel[count * 3 + 2] / pSPARC->SNOSE[0] + pSPARC->ion_vel[count * 3 + 2] / S_new ); // - pSPARC->ion_vel[count * 3] /= S_new; - pSPARC->ion_vel[count * 3 + 1] /= S_new; - pSPARC->ion_vel[count * 3 + 2] /= S_new; - count ++; - } - - //Update kinetic energy and kinetic stress based on new S - pSPARC->KE *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; - - for (int i = 0; i < 9; i++){ - pSPARC->kinetic_stress[i] *= pSPARC->SNOSE[0] * pSPARC->SNOSE[0] / S_new / S_new; - } - - // Update SNOSE[0] to S_new - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_new; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - - -} - - - - -void compute_constraint_stress(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - else{ - baro_const4 = pSPARC->SNOSE[0] / (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); // M_G*det(G) in the Hernandez paper - } - - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPTscaleVecs[2] == 0 && pSPARC->NPTconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPTscaleVecs[0] == 0 && pSPARC->NPTscaleVecs[1] == 0 && pSPARC->NPTscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - else { - if (pSPARC->NPHconstraintFlag == 4){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHconstraintFlag == 1){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (pSPARC->NPHscaleVecs[2] == 0 && pSPARC->NPHconstraintFlag == 1){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - else if (pSPARC->NPHscaleVecs[0] == 0 && pSPARC->NPHscaleVecs[1] == 0 && pSPARC->NPHscaleVecs[2] == 1){ - gpig[0] = 0; - gpig[4] = 0; - } - } - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) * pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) * pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0 / baro_const4, gpi, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int i = 0; i < 9; i++){ - pSPARC->constraint_stress[i] = thermo_const1 * (pSPARC->Pm_metric_tensor[i] - gpig[i]); - pSPARC->Pm_metric_tensor[i] = gpig[i]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11; - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - } - else{ - baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPH_bmass); - } - - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = pSPARC->metric_tensor[i]; - gpig_old[i] = gpig[i]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * ( temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * ( temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * ( temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3, temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int i = 0; i < 9; i++){ - new_metric_tensor[i] = pSPARC->metric_tensor[i] + baro_const6 * gpig_old[i] + baro_const7 * gpig[i]; - } - - converged = true; - for (int i = 0; i < 9; i++){ - if ( fabs(new_metric_tensor[i] - temp_metric_tensor[i]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - transpose_and_add(new_metric_tensor); - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row * 3], - new_metric_tensor[row * 3 + 1], new_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->NPT_NP_ANGLES == 0){ - if (pSPARC->NPTconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPTconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0] ); - b_norm = sqrt( new_metric_tensor[4] ); - c_norm = sqrt( new_metric_tensor[8] ); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - else { - if (pSPARC->NPH_ANGLES == 0){ - if (pSPARC->NPHconstraintFlag == 4){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (pSPARC->NPHconstraintFlag == 1){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - } - - for (int i = 0; i < 9; i++){ - temp_metric_tensor[i] = new_metric_tensor[i]; - } - } - - for (int i = 0; i < 9; i++){ - pSPARC->metric_tensor[i] = temp_metric_tensor[i]; - } - - #ifdef DEBUG - if (rank == 0) { - for (int i = 0; i < 9; i++){ - printf("pSPARC->metric_tensor[%d] is %12.9f\n", i, pSPARC->metric_tensor[i]); - } - } - #endif - -} - - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC, double* internal_stress_fractional){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const0, baro_const3, baro_const5; - - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - else{ - baro_const0 = 0.5 * (pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - baro_const3 = 0.5 / baro_const0; - baro_const5 = baro_const0 * pSPARC->NPH_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - } - - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, - temp_Pm_metric_tensor, 3, - pSPARC->metric_tensor, 3, - 0.0, temp_mat_1, 3); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, - temp_mat_1, 3, - temp_Pm_metric_tensor, 3, - 0.0, temp_mat_2, 3); - - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const0 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int i = 0; i < 9; i++){ - temp_mat[i] = internal_stress_fractional[i] - pSPARC->kinetic_stress[i] + temp_mat_2[i]; - temp_mat[i] += (0.5 * pSPARC->pressure_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[i] + 0.5 * pSPARC->external_stress_lattice[i]; - new_Pm_metric_tensor[i] = pSPARC->Pm_metric_tensor[i] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[i]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor); - - //Check convergence - converged = true; - for (int ic1 = 0; ic1 < 9; ic1++){ - if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int i = 0; i < 9; i++){ - temp_Pm_metric_tensor[i] = new_Pm_metric_tensor[i]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row * 3 + 0], - new_Pm_metric_tensor[row * 3 + 1], new_Pm_metric_tensor[row * 3 + 2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - - } - - // As converged, update the metric tensor momenta - for (int i = 0; i < 9; i++){ - pSPARC->Pm_metric_tensor[i] = temp_Pm_metric_tensor[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_metric_tensor[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_metric_tensor[i]); - #endif - } -} - - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); - } - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH")==0){ - fprintf(output_md,":Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree \n"); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - fprintf(output_md,":Desc_LatUVec: Lattice vectors of unit length, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } else { - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 \n"); - fprintf(output_md,":Desc_LatVec: Lattice vectors, purpose: to represent change in angles during %s ensemble. Unit = Bohr \n",pSPARC->MDMeth); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); - else - fprintf(output_md,":Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0. Unit = Ha/atom \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPH") == 0) - fprintf(output_md,":NPH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPH/pSPARC->n_atom); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(output_md,":ANGLES:\n"); - fprintf(output_md," %.3f %.3f %.3f\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(output_md,":CELL:\n"); - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(output_md,":LatUVec: \n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(output_md,":LATVEC_SCALE:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_md,":LatVec:\n"); - fprintf(output_md," %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the quantities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE/pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - // Compute Ionic stress/pressure - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(9, sizeof(double)); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - printf("\n"); - printf("\n"); - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":SNOSE[1]: %.15g\n", pSPARC->SNOSE[1]); // velocity of virtual thermal parameter - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":SNOSE[0]: %.15g\n", pSPARC->SNOSE[0]); // value of virtual thermal parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - // Print extended system parameters in case of NPH - if(strcmpi(pSPARC->MDMeth,"NPH") == 0){ - fprintf(mdout,":NPH_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":Pm_metric_tensor: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->Pm_metric_tensor[0], pSPARC->Pm_metric_tensor[1], pSPARC->Pm_metric_tensor[2] - , pSPARC->Pm_metric_tensor[3], pSPARC->Pm_metric_tensor[4], pSPARC->Pm_metric_tensor[5] - , pSPARC->Pm_metric_tensor[6], pSPARC->Pm_metric_tensor[7], pSPARC->Pm_metric_tensor[8]); // Momentum of virtual baro parameter - fprintf(mdout,":lattice_avg_velo: %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", pSPARC->lattice_avg_velo[0], pSPARC->lattice_avg_velo[1], pSPARC->lattice_avg_velo[2] - , pSPARC->lattice_avg_velo[3], pSPARC->lattice_avg_velo[4], pSPARC->lattice_avg_velo[5] - , pSPARC->lattice_avg_velo[6], pSPARC->lattice_avg_velo[7], pSPARC->lattice_avg_velo[8]); // velocity of lattice - if (pSPARC->Flag_latvec_scale == 0){ - fprintf(mdout,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - fprintf(mdout,":LatUVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatUVec[0],pSPARC->LatUVec[1],pSPARC->LatUVec[2] - , pSPARC->LatUVec[3],pSPARC->LatUVec[4],pSPARC->LatUVec[5] - , pSPARC->LatUVec[6],pSPARC->LatUVec[7],pSPARC->LatUVec[8]); - } else { - fprintf(mdout,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":LatVec: %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n %18.10E %18.10E %18.10E\n", pSPARC->LatVec[0],pSPARC->LatVec[1],pSPARC->LatVec[2] - , pSPARC->LatVec[3],pSPARC->LatVec[4],pSPARC->LatVec[5] - , pSPARC->LatVec[6],pSPARC->LatVec[7],pSPARC->LatVec[8]); - } - fprintf(mdout,":ANGLES: %18.10E %18.10E %18.10E\n", pSPARC->angle_12, pSPARC->angle_13, pSPARC->angle_23); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,"TARGET_STRESS: %.15g %.15g %.15g %.15g %.15g %.15g GPa\n",(pSPARC->pressure_external+pSPARC->stress_external[0]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[1]) * 29421.02648438959 - ,(pSPARC->pressure_external+pSPARC->stress_external[2]) * 29421.02648438959 - ,pSPARC->stress_external[3] * 29421.02648438959 - ,pSPARC->stress_external[4] * 29421.02648438959 - ,pSPARC->stress_external[5] * 29421.02648438959); - fprintf(mdout,":NPH_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPH); - } - // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) || (strcmpi(pSPARC->MDMeth,"NPH") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - - \ No newline at end of file From 0de633c19416ba7f2e56dbaf52c236a6b41a3369 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 17:15:08 -0400 Subject: [PATCH 79/87] Delete src/include/md_copy_metric_tensor_extra_used.c --- .../md_copy_metric_tensor_extra_used.c | 3435 ----------------- 1 file changed, 3435 deletions(-) delete mode 100644 src/include/md_copy_metric_tensor_extra_used.c diff --git a/src/include/md_copy_metric_tensor_extra_used.c b/src/include/md_copy_metric_tensor_extra_used.c deleted file mode 100644 index d1017a2a..00000000 --- a/src/include/md_copy_metric_tensor_extra_used.c +++ /dev/null @@ -1,3435 +0,0 @@ -/** - * @file md.c - * @brief This file contains the functions for performing molecular dynamics. - * - * @author Phanish Suryanarayana - * Abhiraj Sharma - * Copyright (c) 2017 Material Physics & Mechanics Group at Georgia Tech. - */ - -#include -#include -#include -#include -#include - -#ifdef USE_MKL - #include -#else - #include - #include -#endif - -#include "md.h" -#include "isddft.h" -#include "orbitalElecDensInit.h" -#include "initialization.h" -#include "electronicGroundState.h" -#include "stress.h" -#include "tools.h" -#include "pressure.h" -#include "relax.h" -#include "electrostatics.h" -#include "readfiles.h" -#include "eigenSolver.h" // Mesh2ChebDegree -#include "readfiles.h" -#include "sparc_mlff_interface.h" - -#define max(a,b) ((a)>(b)?(a):(b)) - -//TODO: Implement the case when some atom coordinates are held fixed -/** - @ brief: Main function of MD -**/ -void main_MD(SPARC_OBJ *pSPARC) { - int rank; - int print_restart_typ = 0; - double t_init, t_acc, *avgvel, *maxvel, *mindis; - t_init = MPI_Wtime(); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - avgvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - maxvel = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - mindis = (double *)malloc(pSPARC->Ntypes*(pSPARC->Ntypes+1)/2 * sizeof(double) ); - - // Check whether the restart has to be performed - if(pSPARC->RestartFlag != 0){ - // Check if .restart file present - if(rank == 0){ - FILE *rst_fp = NULL; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - - if(rst_fp == NULL) - pSPARC->RestartFlag = 0; - } - MPI_Bcast(&pSPARC->RestartFlag, 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (pSPARC->RestartFlag != 0) { - RestartMD(pSPARC); - int atm; - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - Cart2nonCart_coord(pSPARC, &pSPARC->atom_pos[3*atm], &pSPARC->atom_pos[3*atm+1], &pSPARC->atom_pos[3*atm+2]); - } - } - } - } - - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - Initialize_MD(pSPARC); - - pSPARC->MD_maxStep = pSPARC->restartCount + pSPARC->MD_Nstep; - - // File output_md stores all the desirable properties from a MD run - FILE *output_md, *output_fp; - if (pSPARC->PrintMDout == 1 && !rank && pSPARC->MD_Nstep > 0){ - output_md = fopen(pSPARC->MDFilename,"w"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - pSPARC->MDCount = -1; - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - pSPARC->MDCount++; - - if(pSPARC->RestartFlag == 0){ - fprintf(output_md,":MDSTEP: %d\n", 1); - fprintf(output_md,":MDTM: %.2f\n", (MPI_Wtime() - t_init)); - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the output_md file - } - - fclose(output_md); - } - - if (!rank && pSPARC->MD_Nstep > 0) { - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount++; - pSPARC->elecgs_Count++; - - // Perform MD until maxStep is reached or total walltime is hit - int Count = pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0); // Count is the MD step no. to be performed - int check1 = (pSPARC->PrintMDout == 1 && !rank); - int check2 = (pSPARC->Printrestart == 1 && !rank); - t_acc = (MPI_Wtime() - t_init)/60;// tracks time in minutes - while(Count <= pSPARC->MD_maxStep && (t_acc + 1.0*(MPI_Wtime() - t_init)/60) < pSPARC->TWtime){ - t_init = MPI_Wtime(); -#ifdef DEBUG - if(!rank) printf(":MDSTEP: %d\n", Count); -#endif - if (check1){ - output_md = fopen(pSPARC->MDFilename,"a+"); - if (output_md == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->MDFilename); - exit(EXIT_FAILURE); - } - fprintf(output_md,":MDSTEP: %d\n", Count); - } - - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0) - NVT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVE") == 0) - NVE(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NVK_G") == 0) - NVK_G(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - NPT_NH(pSPARC); - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - NPT_NP(pSPARC); - else{ - if (!rank){ - printf("\nCannot recognize MDMeth = \"%s\"\n",pSPARC->MDMeth); - } - exit(EXIT_FAILURE); - } - - MD_QOI(pSPARC, avgvel, maxvel, mindis); // calculates the quantities of interest in an MD simulation - - if(check1) { - fprintf(output_md,":MDTM: %.2f\n", MPI_Wtime() - t_init); - Print_fullMD(pSPARC, output_md, avgvel, maxvel, mindis); // prints the QOI in the .aimd file - } if(check2 && !(Count % pSPARC->Printrestart_fq)) // printrestart_fq is the frequency at which the restart file is written - PrintMD(pSPARC, 1, print_restart_typ); - - if(access("SPARC.stop", F_OK ) != -1 ){ // If a .stop file exists in the folder then the run will be terminated - pSPARC->MDCount++; - break; - } - if(check1) - fclose(output_md); -#ifdef DEBUG - if (!rank) printf("Time taken by MDSTEP %d: %.3f s.\n", Count, (MPI_Wtime() - t_init)); -#endif - if(!rank){ - output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"MD step time : %.3f (sec)\n", (MPI_Wtime() - t_init)); - fclose(output_fp); - } - - pSPARC->MDCount ++; - Count ++; - t_acc += (MPI_Wtime() - t_init)/60; - } // end while loop - if(check2){ - pSPARC->MDCount --; - print_restart_typ = 1; - PrintMD(pSPARC, 1, print_restart_typ); - } - free(avgvel); - free(maxvel); - free(mindis); -} - -/** - @ brief: function to initialize velocities and accelerations for Molecular Dynamics (MD) - **/ -void Initialize_MD(SPARC_OBJ *pSPARC) { - int ityp, atm, count, rand_seed = 5; - - if (pSPARC->ion_vel_dstr_rand == 1) { - // add a time-dependent component to the seed - rand_seed += (int)MPI_Wtime(); - } - - pSPARC->ion_accel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_accel == NULL) { - printf("\nCannot allocate memory for ion acceleration array!\n"); - exit(EXIT_FAILURE); - } - - int count_x = 0; - int count_y = 0; - int count_z = 0; - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++) { - count_x += pSPARC->mvAtmConstraint[3 * count]; - count_y += pSPARC->mvAtmConstraint[3 * count + 1]; - count_z += pSPARC->mvAtmConstraint[3 * count + 2]; - count++; - } - pSPARC->dof = (count_x - (count_x == pSPARC->n_atom)) + (count_y - (count_y == pSPARC->n_atom)) - + (count_z - (count_z == pSPARC->n_atom)); // TODO: Create a user defined variable dof with this as a default value - - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) - pSPARC->Mass[ityp] *= pSPARC->amu2au; // mass in atomic units - - pSPARC->MD_dt *= pSPARC->fs2atu; // time in atomic time units - - // Variables for NVT_NH - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0 && pSPARC->RestartFlag != 1){ - pSPARC->snose = 0.0; - pSPARC->xi_nose = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - } - // Variables for NPT_NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 && pSPARC->RestartFlag != 1){ - int i; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if((pSPARC->NPT_NHnnos == 0) || (pSPARC->NPT_NHnnos > L_QMASS)) { - if (!rank) { - printf("Amount of thermostat variables cannot be zero or larger than %d. Please write valid amount of thermo variable (int) at head of input line.\n", L_QMASS); - printf("Example as below\n"); - printf("NPT_NH_QMASS: 4 1500.0 1500.0 1500.0 1500.0\n"); - exit(EXIT_FAILURE); - } - } - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - if (pSPARC->NPT_NHqmass[subscript_NPTNH_qmass] == 0.0 && !rank){ - printf("Mass of thermostat variable %d cannot be zero. Please input valid amount of mass of thermo variable.\n", subscript_NPTNH_qmass); - exit(EXIT_FAILURE); - } - } - if(pSPARC->NPT_NHbmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - pSPARC->vlogs[i] = 0.0; - pSPARC->xlogs[i] = 0.0; - } - pSPARC->vlogv = 0.0; - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - pSPARC->scale = 1.0; - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { // restart - if ((pSPARC->NPTscaleVecs[0] == 1) && (pSPARC->NPTscaleVecs[1] == 1) && (pSPARC->NPTscaleVecs[2] == 1)) pSPARC->NPTisotropicFlag = 1; - else pSPARC->NPTisotropicFlag = 0; - int i; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->glogs[i] = 0.0; - } - // pSPARC->thermos_Ti = pSPARC->ion_T; // ion_T is decided by the kinetic energy of particles at that time step, changing with time - // pSPARC->thermos_Ti = pSPARC->elec_T; // It comes from restart file - pSPARC->thermos_T = pSPARC->thermos_Ti; - pSPARC->prtarget /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - Calculate_ionic_stress(pSPARC); - } - // Variables for NPT_NP and NPH - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0 && pSPARC->RestartFlag != 1){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - if(pSPARC->NPT_NP_bmass == 0.0) { - if (!rank) { - printf("Mass of barostat variable cannot be zero. Please input valid amount of mass of baro variable.\n"); - exit(EXIT_FAILURE); - } - } - - //Calculate metric_tensor G, reciprocal metric tensor, angles between lattice vectors, rotation matrix - fetch_MD_cell_ingredients(pSPARC); - - pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i1 = 0; i1 < 6; i1++){ - pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - } - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 && (pSPARC->NPT_NP_qmass == 0.0)){ - if (!rank) { - printf("Mass of thermostat variable cannot be zero in NPT_NP ensemble. Please input valid amount of mass of thermo variable. Using a zero mass would resemble NPH ensemble, if this is the case then please choose MD_METHOD as NPH \n"); - exit(EXIT_FAILURE); - } - } - - if(strcmpi(pSPARC->MdMeth,"NPH")){ - pSPARC->NPT_NPH_qmass = 0 - if (!rank) { - printf("Mass of thermostat variable is zero in NPH ensemble. If choosing MD_method as NPH with nonzero thermostat mass, it would be automatically set to zero at this point\n"); - } - } - - pSPARC->SNOSE[0] = 1.0; // S variable of the thermostat @ current timestep (t) - pSPARC->SNOSE[1] = 0.0; // Ps/Ms or initial velocity of thermostat - pSPARC->SNOSE[2] = SNOSE[0]; // S variable of the thermostat @ previous timestep (t-dt) - - pSPARC->thermos_Ti = pSPARC->ion_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; - - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0 || strcmpi(pSPARC->MDMeth,"NPH") == 0) { // restart - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - pSPARC->maxTimeIter = 30; - - fetch_MD_cell_ingredients(pSPARC); - - // pSPARC->thermos_Ti = pSPARC->elec_T; - pSPARC->thermos_T = pSPARC->thermos_Ti; // It comes from restart file! - pSPARC->pr_external /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - for (int i1 = 0; i1 < 6; i1++){ - pSPARC->stress_external[i1] /= 29421.02648438959; // transfer from GPa to Ha/Bohr^3 - }// transfer from GPa to Ha/Bohr^3 - pSPARC->external_stress_cartesian[0] = pSPARC->stress_external[0]; - pSPARC->external_stress_cartesian[4] = pSPARC->stress_external[1]; - pSPARC->external_stress_cartesian[8] = pSPARC->stress_external[2]; - pSPARC->external_stress_cartesian[1] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[2] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[3] = pSPARC->stress_external[3]; - pSPARC->external_stress_cartesian[5] = pSPARC->stress_external[5]; - pSPARC->external_stress_cartesian[6] = pSPARC->stress_external[4]; - pSPARC->external_stress_cartesian[7] = pSPARC->stress_external[5]; - - if(strcmpi(pSPARC->MdMeth,"NPH")){ - pSPARC->NPT_NPH_qmass = 0 - } - - Calculate_ionic_stress(pSPARC); - } - - if(pSPARC->RestartFlag == 0){ - double mass_sum = 0.0, mvsum_x, mvsum_y, mvsum_z; - mvsum_x = mvsum_y = mvsum_z = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mass_sum += pSPARC->Mass[ityp] * pSPARC->nAtomv[ityp]; - } - if(pSPARC->ion_vel_dstr != 3){ // initial velocity of ions is not explicitly provided by the user - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - } - // Uniform velocity distribution - if(pSPARC->ion_vel_dstr == 1){ - double vel_cm, s = 2.0, x = 0.0, y = 0.0; // vel_cm: center of mass velocity in Bohr/atu - vel_cm = sqrt((pSPARC->dof * pSPARC->ion_T * pSPARC->kB)/mass_sum); - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - while(s>1.0){ - x = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; // random number between -1 and +1 - y = 2.0 * ((double)(rand()) / (double)(RAND_MAX)) - 1; - s = x * x + y * y; - } - pSPARC->ion_vel[count * 3 + 2] = vel_cm * (1.0 - 2.0 * s); - s = 2.0 * sqrt(1.0 - s); - pSPARC->ion_vel[count * 3 + 1] = s * y * vel_cm; - pSPARC->ion_vel[count * 3] = s * x * vel_cm; - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - }else if(pSPARC->ion_vel_dstr == 2) // Maxwell-Boltzmann distribution of velocity (Default!) - { - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - srand(ityp + rand_seed);// random seed (default 5). Seed has to be common across all processors!! - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos(2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 1] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] = sqrt(pSPARC->kB * pSPARC->ion_T/pSPARC->Mass[ityp]) * cos( 2 * M_PI * ((double)(rand()) / (double)(RAND_MAX))); - pSPARC->ion_vel[count * 3 + 2] *= sqrt(-2.0 * log((double)(rand()) / (double)(RAND_MAX))); - mvsum_x += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3]; - mvsum_y += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 1]; - mvsum_z += pSPARC->Mass[ityp] * pSPARC->ion_vel[count * 3 + 2]; - count += 1; - } - } - } - - // Remove translation (rotation not possible in case of PBC) TODO: angular velocity in other types of boundary conditions - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] -= mvsum_x/mass_sum; - pSPARC->ion_vel[count * 3 + 1] -= mvsum_y/mass_sum; - pSPARC->ion_vel[count * 3 + 2] -= mvsum_z/mass_sum; - count += 1; - } - } - - // Zeroing the velocity for fixed atoms - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= pSPARC->mvAtmConstraint[count * 3]; - pSPARC->ion_vel[count * 3 + 1] *= pSPARC->mvAtmConstraint[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] *= pSPARC->mvAtmConstraint[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - - // Rescale velocities - double rescal_fac ; - rescal_fac = sqrt(pSPARC->dof * pSPARC->kB * pSPARC->ion_T/(2.0 * pSPARC->KE)) ; - pSPARC->KE = 0.0; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 1] *= rescal_fac; - pSPARC->ion_vel[count * 3 + 2] *= rescal_fac; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count += 1; - } - } - } - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - count += 1; - } - } - -#ifdef DEBUG - // Statistics to be set to zero initially - pSPARC->mean_TE_ext = pSPARC->std_TE_ext = 0.0; - pSPARC->mean_elec_T = pSPARC->mean_ion_T = pSPARC->mean_TE = pSPARC->mean_KE = pSPARC->mean_PE = pSPARC->mean_U = pSPARC->mean_Entropy = 0.0; - pSPARC->std_elec_T = pSPARC->std_ion_T = pSPARC->std_TE = pSPARC->std_KE = pSPARC->std_PE = pSPARC->std_U = pSPARC->std_Entropy = 0.0; -#endif -} - -/* -@ brief function to perform NVT MD simulation with Nose hoover thermostat wherein number of particles, volume and temperature are kept constant (equivalent to ionmov = 8 in ABINIT) -*/ -void NVT_NH(SPARC_OBJ *pSPARC) { - double fsnose; - // First step velocity Verlet - VVerlet1(pSPARC); - // Update thermostat - pSPARC->thermos_T = pSPARC->thermos_Ti + ((pSPARC->thermos_Tf - pSPARC->thermos_Ti)/(pSPARC->MD_Nstep)) * (pSPARC->MDCount); - fsnose = (pSPARC->v2nose - pSPARC->dof * pSPARC->kB * pSPARC->thermos_T)/pSPARC->qmass; - pSPARC->snose += pSPARC->MD_dt * (pSPARC->xi_nose + 0.5 * pSPARC->MD_dt * fsnose); - pSPARC->xi_nose += 0.5 * pSPARC->MD_dt * fsnose; - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Second step velocity Verlet - VVerlet2(pSPARC); -} - -/* -@ brief: function to perform first step of velocity verlet algorithm -*/ -void VVerlet1(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3]); - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 1]); - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - pSPARC->xi_nose * pSPARC->ion_vel[count * 3 + 2]); - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } -} - -/* -@ brief: function to perform second step of velocity verlet algorithm -*/ -void VVerlet2(SPARC_OBJ* pSPARC) { - int ityp, atm, count = 0, ready = 0, kk, jj; - double *vel_temp, *vonose, *hnose, *binose, xin_nose, xio, delxi, dnose ; - vel_temp = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - vonose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - hnose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - binose = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - xin_nose = pSPARC->xi_nose; - pSPARC->v2nose = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - //a(t+dt) = F(t+dt)/M - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - vel_temp[count * 3] = pSPARC->ion_vel[count * 3]; - vel_temp[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1]; - vel_temp[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - } - do { - xio = xin_nose ; - delxi = 0.0 ; - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vonose[count * 3] = vel_temp[count * 3] ; - vonose[count * 3 + 1] = vel_temp[count * 3 + 1] ; - vonose[count * 3 + 2] = vel_temp[count * 3 + 2] ; - hnose[count * 3] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3] - xio * vonose[count * 3]) - (pSPARC->ion_vel[count * 3] - vonose[count * 3]); - hnose[count * 3 + 1] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 1] - xio * vonose[count * 3 + 1]) - (pSPARC->ion_vel[count * 3 + 1] - vonose[count * 3 + 1]); - hnose[count * 3 + 2] = -0.5 * pSPARC->MD_dt * (pSPARC->ion_accel[count * 3 + 2] - xio * vonose[count * 3 + 2]) - (pSPARC->ion_vel[count * 3 + 2] - vonose[count * 3 + 2]); - binose[count * 3] = vonose[count * 3] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3] * binose[count * 3] ; - binose[count * 3 + 1] = vonose[count * 3 + 1] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 1] * binose[count * 3 + 1] ; - binose[count * 3 + 2] = vonose[count * 3 + 2] * pSPARC->MD_dt * pSPARC->Mass[ityp]/pSPARC->qmass ; - delxi += hnose[count * 3 + 2] * binose[count * 3 + 2] ; - count ++; - } - } - dnose = -1.0 * (0.5 * xio * pSPARC->MD_dt + 1.0) ; - delxi += -1.0 * dnose * ((-1.0 * pSPARC->v2nose + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T) * 0.5 * pSPARC->MD_dt/pSPARC->qmass - (pSPARC->xi_nose - xio)) ; - delxi /= (-0.5 * pow(pSPARC->MD_dt,2.0) * pSPARC->v2nose/pSPARC->qmass + dnose) ; - pSPARC->v2nose = 0.0 ; - count = 0 ; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - vel_temp[count * 3] += (hnose[count * 3] + 0.5 * pSPARC->MD_dt * vonose[count * 3] * delxi)/dnose ; - vel_temp[count * 3 + 1] += (hnose[count * 3 + 1] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 1] * delxi)/dnose ; - vel_temp[count * 3 + 2] += (hnose[count * 3 + 2] + 0.5 * pSPARC->MD_dt * vonose[count * 3 + 2] * delxi)/dnose ; - pSPARC->v2nose += pSPARC->Mass[ityp] * (pow(vel_temp[count * 3], 2.0) + pow(vel_temp[count * 3 + 1], 2.0) + pow(vel_temp[count * 3 + 2], 2.0)); - count ++; - } - } - xin_nose = xio + delxi ; - ready = 1 ; - //Test for convergence - kk = -1, jj = 0; - do{ - kk = kk + 1 ; - if(kk >= pSPARC->n_atom){ - kk = 0; - jj ++; - } - if(kk < pSPARC->n_atom && jj < 3){ - //if (fabs(vel_temp[kk + jj*pSPARC->n_atom]) < 1e-50) - // vel_temp[kk + jj*pSPARC->n_atom] = 1e-50 ; - if(fabs((vel_temp[kk + jj * pSPARC->n_atom] - vonose[kk + jj * pSPARC->n_atom])/vel_temp[kk + jj * pSPARC->n_atom]) > 1e-7) - ready = 0 ; - } - else{ - //if (fabs(xin_nose) < 1e-50) - // xin_nose = 1e-50 ; - if(fabs((xin_nose - xio)/xin_nose) > 1e-7) - ready = 0 ; - } - } while(kk < pSPARC->n_atom && jj < 3 && ready); - } while (ready == 0); - - pSPARC->xi_nose = xin_nose ; - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = vel_temp[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = vel_temp[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = vel_temp[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - free(vel_temp); - free(vonose); - free(binose); - free(hnose); -} - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and total energy(P.E.(calculated quantum mechanically) + K.E. of ions(Calculated classically)) constant. - **/ -void NVE(SPARC_OBJ *pSPARC) { - // Leapfrog step - 1 - Leapfrog_part1(pSPARC); - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - // Leapfrog step (part-2) - Leapfrog_part2(pSPARC); -} - -/* -@ brief: function to update position of atoms using Leapfrog method -*/ -void Leapfrog_part1(SPARC_OBJ *pSPARC) { - /******************************************************** - // Leapfrog algorithm - PART-I (Implemented in this function) - v_(t+dt/2) = v_t + 0.5*dt*a_t - r_(t+dt) = r_t + dt*v_(t+dt/2) - - PART-II (Implemented in the next function, after computing - a_(t+dt) for current positions) - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - **********************************************************/ - int count = 0, atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - // v_(t+dt/2) = v_t + 0.5*dt*a_t - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - // r_(t+dt) = r_t + dt*v_(t+dt/2) - pSPARC->atom_pos[count * 3] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3]; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 1]; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->MD_dt * pSPARC->ion_vel[count * 3 + 2]; - count ++; - } - -} - -/* - @ brief: function to update velocity of atoms using Leapfrog method -*/ -void Leapfrog_part2(SPARC_OBJ *pSPARC) { - /************************************ - PART-II Leapfrog algorithm - v_(t+dt) = v_(t+dt/2) + 0.5*dt*a_(t+dt) - *************************************/ - int count = 0, ityp, atm; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - -} - - -/** - @ brief: Perform molecular dynamics keeping number of particles, volume of the cell and kinetic energy constant i.e. NVK with Gaussian thermostat. - It is based on the implementation in ABINIT (ionmov=12) - **/ -void NVK_G(SPARC_OBJ *pSPARC) { - // Calculate velocity at next half time step - Calc_vel1_G(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPSPARC); - pSPARC->elecgs_Count++; - - // Calculate velocity at next full time step - Calc_vel2_G(pSPARC); -} - - -/* - @ brief: calculate velocity at next half time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel1_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - - pSPARC->atom_pos[count * 3] += pSPARC->ion_vel[count * 3] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 1] += pSPARC->ion_vel[count * 3 + 1] * pSPARC->MD_dt; - pSPARC->atom_pos[count * 3 + 2] += pSPARC->ion_vel[count * 3 + 2] * pSPARC->MD_dt; - count ++; - } - } -} - - -/* - @ brief: calculate velocity at next full time step for isokinetic ensemble with Gaussian thermostat -*/ - -void Calc_vel2_G(SPARC_OBJ *pSPARC) { - double v2gauss = 0.0; - double a = 0.0; - double b = 0.0; - int ityp, atm, count = 0; - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - - v2gauss += (pSPARC->ion_vel[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->ion_vel[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->ion_vel[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2]) * pSPARC->Mass[ityp] ; - - a += pSPARC->forces[count * 3] * pSPARC->ion_vel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_vel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_vel[count * 3 + 2] ; - - b += pSPARC->forces[count * 3] * pSPARC->ion_accel[count * 3] + - pSPARC->forces[count * 3 + 1] * pSPARC->ion_accel[count * 3 + 1] + - pSPARC->forces[count * 3 + 2] * pSPARC->ion_accel[count * 3 + 2] ; - - count ++; - } - } - - a /= v2gauss; - b /= v2gauss; - - double sqb = sqrt(b); - double as = sqb * pSPARC->MD_dt/2.0; - if(as > 300.0) - as = 300.0; - - double s1 = cosh(as); - double s2 = sinh(as); - double s = a * (s1-1.0)/b + s2/sqb; - double scdot = a * s2/sqb + s1; - - count = 0; - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count * 3] = (pSPARC->ion_vel[count * 3] + pSPARC->ion_accel[count * 3] * s)/scdot; - pSPARC->ion_vel[count * 3 + 1] = (pSPARC->ion_vel[count * 3 + 1] + pSPARC->ion_accel[count * 3 + 1] * s)/scdot; - pSPARC->ion_vel[count * 3 + 2] = (pSPARC->ion_vel[count * 3 + 2] + pSPARC->ion_accel[count * 3 + 2] * s)/scdot; - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } -} - -/* -@ brief function to perform NPT MD simulation with Nose hoover chain. -wherein number of particles, pressure and temperature are kept constant (equivalent to ionmov = 13, optcell = 1 in ABINIT) -reference: Glenn J. Martyna , Mark E. Tuckerman , Douglas J. Tobias & Michael L. Klein (1996). -Explicit reversible integrators for extended systems dynamics, Molecular Physics, 87:5 -Tuckerman, M. E., Alejandre, J., López-Rendón, R., Jochim, A. L., & Martyna, G. J. (2006). -A Liouville-operator derived measure-preserving integrator for molecular dynamics simulations in the isothermal–isobaric ensemble. -Journal of Physics A: Mathematical and General, 39(19), 5629. -*/ -void NPT_NH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->pres, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->pres_i, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - if ((pSPARC->MDCount != 1) || (pSPARC->RestartFlag == 1)) { - // Update velocity of particles in the second half timestep - AccelVelocityParticle(pSPARC); - // Update velocity of virtual thermo and baro variables in the second half timestep - IsoPress(pSPARC); - } - - // Update velocity of virtual thermo and baro variables in the first half timestep - IsoPress(pSPARC); - // Update velocity of particles in the first half timestep - AccelVelocityParticle(pSPARC); - // Update position of particles and size of cell in the timestep - PositionParticleCell(pSPARC); - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - // Calculate Hamiltonian of the system. - hamiltonian_NPT_NH(pSPARC); - if (rank == 0){ - printf("\nend NPT timestep %d\n", pSPARC->MDCount + 1); - } - #endif - -} - -/* -@ brief function to update accelerations and velocities of particles changed by forces in NPT -*/ -void AccelVelocityParticle (SPARC_OBJ *pSPARC) { - int ityp, atm, count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1]/pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2]/pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] += 0.5 * pSPARC->MD_dt * pSPARC->ion_accel[count * 3 + 2]; - count ++; - } - } -} - - -/* -@ brief function to update accelerations, velocities and positions of virtual thermo and barostat variables in NPT -*/ -void IsoPress(SPARC_OBJ *pSPARC) { - int i, atm, ityp; - int count = 0; - double scale, gn1kt, odnf, modnf, ktemp; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - pSPARC->KE = 0.0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - scale = 1.0; - ktemp = pSPARC->kB * pSPARC->thermos_T; - gn1kt = (double)(pSPARC->dof + 1) * ktemp; - - modnf = 3.0/(double)pSPARC->dof; - odnf = 1.0 + 3.0/(double)pSPARC->dof; - // update accelerations of the virtual variables, 1st - double glogv = 0.0; - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*pSPARC->vlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - - // update velocities of the virtual variables, 1st - double alocal; - double nowvlogv = pSPARC->vlogv; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of baro variable, 2nd - alocal = exp(-pSPARC->MD_dt / 2.0 * (pSPARC->vlogs[0] + odnf * nowvlogv)); - scale = scale * alocal; - pSPARC->KE = pSPARC->KE * pow(alocal, 2.0); - glogv = (3*pSPARC->volumeCell*((pSPARC->pres - pSPARC->pres_i) - pSPARC->prtarget) + modnf*2*pSPARC->KE - pSPARC->vlogs[0]*nowvlogv*pSPARC->NPT_NHbmass) / pSPARC->NPT_NHbmass; - // printf("\nrank %d glogv%12.9f = (odnf%12.6f*2*KE%12.9f+3*(pres%12.9f-prtarget%12.6f)*ucvol%12.9f)/bmass%12.6f\n", rank, glogv,odnf,pSPARC->KE,(pSPARC->pres - pSPARC->pres_i),pSPARC->prtarget,ucvol,pSPARC->NPT_NHbmass); - // update thermostat position, for computing Hamiltonian - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - pSPARC->xlogs[i] += pSPARC->vlogs[i] * pSPARC->MD_dt / 2; - } - // update velocities of the baro variables, 2nd - nowvlogv += pSPARC->MD_dt / 4.0 * glogv; - // update accelerations of thermal variable, 2nd - pSPARC->glogs[0] = ((2.0*pSPARC->KE + pSPARC->NPT_NHbmass * pow(pSPARC->vlogv, 2.0) - gn1kt) - pSPARC->vlogs[1]*pSPARC->vlogs[0]*pSPARC->NPT_NHqmass[0]) / pSPARC->NPT_NHqmass[0]; - for (i = 0; i < pSPARC->NPT_NHnnos; i++) { - pSPARC->vlogs[i] += pSPARC->MD_dt / 4.0 * pSPARC->glogs[i]; - } - for (i = 1; i < pSPARC->NPT_NHnnos - 1; i++) { - pSPARC->glogs[i] = (pSPARC->NPT_NHqmass[i - 1] * pow(pSPARC->vlogs[i - 1], 2.0) - ktemp - pSPARC->vlogs[i + 1]*pSPARC->vlogs[i]*pSPARC->NPT_NHqmass[i]) / pSPARC->NPT_NHqmass[i]; - } - pSPARC->glogs[pSPARC->NPT_NHnnos - 1] = (pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 2]*pow(pSPARC->vlogs[pSPARC->NPT_NHnnos - 2], 2.0) - ktemp) / pSPARC->NPT_NHqmass[pSPARC->NPT_NHnnos - 1]; - // update velocities of particles - count = 0; - for (atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->ion_vel[count * 3] *= scale; - pSPARC->ion_vel[count * 3 + 1] *= scale; - pSPARC->ion_vel[count * 3 + 2] *= scale; - count ++; - } - // send calculated variables back to pSPARC - pSPARC->vlogv = nowvlogv; - #ifdef DEBUG - if (rank == 0){ - printf("rank %d", rank); - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - printf("\nvlogs[%d] is %12.9f; glogs[%d] is %12.9f \n", i, pSPARC->vlogs[i], i, pSPARC->glogs[i]); - } - printf("\nglogv is %12.9f\n", glogv); - printf("\nvlogv is %12.9f\n", nowvlogv); - } - #endif -} - -/* -@ brief function to update positions of particles and size of a cell in NPT -*/ -void PositionParticleCell(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // update particle positions - if (pSPARC->NPTisotropicFlag == 1) { - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = pSPARC->atom_pos[count * 3] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 1] = pSPARC->atom_pos[count * 3 + 1] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 1] * mttk_bloc; - pSPARC->atom_pos[count * 3 + 2] = pSPARC->atom_pos[count * 3 + 2] * pow(mttk_aloc, 2.0) + pSPARC->ion_vel[count * 3 + 2] * mttk_bloc; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv); - pSPARC->range_x *= pSPARC->scale; - pSPARC->range_y *= pSPARC->scale; - pSPARC->range_z *= pSPARC->scale; - } - else { // only 1 or 2 lattice vectors can be rescaled - int dim = pSPARC->NPTscaleVecs[0] + pSPARC->NPTscaleVecs[1] + pSPARC->NPTscaleVecs[2]; - double rescale = 3.0/(double)dim; - - int count, atm; - double mttk_aloc, mttk_aloc2, polysh, mttk_bloc; - mttk_aloc = exp(pSPARC->MD_dt / 2.0 * pSPARC->vlogv * rescale); - mttk_aloc2 = pow(pSPARC->vlogv * pSPARC->MD_dt / 2.0 * rescale, 2.0); - - polysh = (((1.0 / (6.0*20.0*42.0*72.0) * mttk_aloc2 + 1.0 / (6.0*20.0*42.0)) * mttk_aloc2 + 1.0 / (6.0*20.0)) * mttk_aloc2 + 1.0 / 6.0) * mttk_aloc2 + 1.0; - mttk_bloc = mttk_aloc * polysh * pSPARC->MD_dt; - - double *LatUVec = pSPARC->LatUVec; double *gradT = pSPARC->gradT; - double carCoord[3]; double nonCarCoord[3]; // cartisian and reduced coordinate - double carVelo[3]; double nonCarVelo[3]; // cartisian and reduced velocity - count = 0; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - carCoord[0] = pSPARC->atom_pos[count * 3]; carCoord[1] = pSPARC->atom_pos[count * 3 + 1]; carCoord[2] = pSPARC->atom_pos[count * 3 + 2]; - carVelo[0] = pSPARC->ion_vel[count * 3]; carVelo[1] = pSPARC->ion_vel[count * 3 + 1]; carVelo[2] = pSPARC->ion_vel[count * 3 + 2]; - - Cart2nonCart(gradT, carCoord, nonCarCoord); - Cart2nonCart(gradT, carVelo, nonCarVelo); - - if (pSPARC->NPTscaleVecs[0] == 1) nonCarCoord[0] = nonCarCoord[0] * pow(mttk_aloc, 2.0) + nonCarVelo[0] * mttk_bloc; - else nonCarCoord[0] = nonCarCoord[0] + nonCarVelo[0]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[1] == 1) nonCarCoord[1] = nonCarCoord[1] * pow(mttk_aloc, 2.0) + nonCarVelo[1] * mttk_bloc; - else nonCarCoord[1] = nonCarCoord[1] + nonCarVelo[1]*pSPARC->MD_dt; - - if (pSPARC->NPTscaleVecs[2] == 1) nonCarCoord[2] = nonCarCoord[2] * pow(mttk_aloc, 2.0) + nonCarVelo[2] * mttk_bloc; - else nonCarCoord[2] = nonCarCoord[2] + nonCarVelo[2]*pSPARC->MD_dt; - - nonCart2Cart(LatUVec, carCoord, nonCarCoord); - - pSPARC->atom_pos[count * 3] = carCoord[0]; pSPARC->atom_pos[count * 3 + 1] = carCoord[1]; pSPARC->atom_pos[count * 3 + 2] = carCoord[2]; - count ++; - } - // update size of cell - pSPARC->scale = exp(pSPARC->MD_dt * pSPARC->vlogv * rescale); - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->range_x *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->range_y *= pSPARC->scale; - if (pSPARC->NPTscaleVecs[2] == 1) pSPARC->range_z *= pSPARC->scale; - } - #ifdef DEBUG - if(rank == 0){ - printf("rank %d", rank); - printf("scale of cell is %12.9f\n", pSPARC->scale); - printf("pSPARC->range is (%12.9f, %12.9f, %12.9f)\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - } - #endif -} - -/** - * @brief Write the re-initialized parameters into the output file. - */ -void write_output_reinit_NPT(SPARC_OBJ *pSPARC) { - int nproc; - MPI_Comm_size(MPI_COMM_WORLD, &nproc); - - FILE *output_fp = fopen(pSPARC->OutFilename,"a"); - if (output_fp == NULL) { - printf("\nCannot open file \"%s\"\n",pSPARC->OutFilename); - exit(EXIT_FAILURE); - } - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialized parameters \n"); - fprintf(output_fp,"***************************************************************************\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_fp,"CELL: %.15g %.15g %.15g \n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_fp,"LATVEC_SCALE: %.15g %.15g %.15g \n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(output_fp,"CHEB_DEGREE: %d\n",pSPARC->ChebDegree); - fprintf(output_fp,"***************************************************************************\n"); - fprintf(output_fp," Reinitialization \n"); - fprintf(output_fp,"***************************************************************************\n"); - if ( (fabs(pSPARC->delta_x-pSPARC->delta_y) <=1e-12) && (fabs(pSPARC->delta_x-pSPARC->delta_z) <=1e-12) - && (fabs(pSPARC->delta_y-pSPARC->delta_z) <=1e-12) ) { - fprintf(output_fp,"Mesh spacing : %.6g (Bohr)\n",pSPARC->delta_x); - } else { - fprintf(output_fp,"Mesh spacing in x-direction : %.6g (Bohr)\n",pSPARC->delta_x); - fprintf(output_fp,"Mesh spacing in y-direction : %.6g (Bohr)\n",pSPARC->delta_y); - fprintf(output_fp,"Mesh spacing in z direction : %.6g (Bohr)\n",pSPARC->delta_z); - } - - fclose(output_fp); -} - -/* -@ brief reinitialize related variables after the size changing of cell. -*/ -void reinitialize_mesh_NPT(SPARC_OBJ *pSPARC) -{ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - -#ifdef DEBUG - double t1, t2; -#endif - - int p, i; - // scaling factor - double scal = pSPARC->scale; // the ratio between length -#ifdef DEBUG - if(rank == 0){ - printf("scal: %12.6f\n", scal); - } -#endif - - pSPARC->delta_x = pSPARC->range_x/(pSPARC->numIntervals_x); - pSPARC->delta_y = pSPARC->range_y/(pSPARC->numIntervals_y); - pSPARC->delta_z = pSPARC->range_z/(pSPARC->numIntervals_z); - - - pSPARC->dV = pSPARC->delta_x * pSPARC->delta_y * pSPARC->delta_z * pSPARC->Jacbdet; - -#ifdef DEBUG - if (!rank) { - // printf("Volume: %12.6f\n", vol); - printf("CELL : %12.6f\t%12.6f\t%12.6f\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - printf("COORD : \n"); - for (i = 0; i < 3 * pSPARC->n_atom; i++) { - printf("%12.6f\t",pSPARC->atom_pos[i]); - if (i%3==2 && i>0) printf("\n"); - } - printf("\n"); - } -#endif - - int FDn = pSPARC->order / 2; - - // 1st derivative weights including mesh - double dx_inv, dy_inv, dz_inv; - dx_inv = 1.0 / pSPARC->delta_x; - dy_inv = 1.0 / pSPARC->delta_y; - dz_inv = 1.0 / pSPARC->delta_z; - for (p = 1; p < FDn + 1; p++) { - pSPARC->D1_stencil_coeffs_x[p] = pSPARC->FDweights_D1[p] * dx_inv; - pSPARC->D1_stencil_coeffs_y[p] = pSPARC->FDweights_D1[p] * dy_inv; - pSPARC->D1_stencil_coeffs_z[p] = pSPARC->FDweights_D1[p] * dz_inv; - } - - // 2nd derivative weights including mesh - double dx2_inv, dy2_inv, dz2_inv; - dx2_inv = 1.0 / (pSPARC->delta_x * pSPARC->delta_x); - dy2_inv = 1.0 / (pSPARC->delta_y * pSPARC->delta_y); - dz2_inv = 1.0 / (pSPARC->delta_z * pSPARC->delta_z); - - // Stencil coefficients for mixed derivatives - if (pSPARC->cell_typ == 0) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->FDweights_D2[p] * dz2_inv; - } - } else if (pSPARC->cell_typ > 10 && pSPARC->cell_typ < 20) { - for (p = 0; p < FDn + 1; p++) { - pSPARC->D2_stencil_coeffs_x[p] = pSPARC->lapcT[0] * pSPARC->FDweights_D2[p] * dx2_inv; - pSPARC->D2_stencil_coeffs_y[p] = pSPARC->lapcT[4] * pSPARC->FDweights_D2[p] * dy2_inv; - pSPARC->D2_stencil_coeffs_z[p] = pSPARC->lapcT[8] * pSPARC->FDweights_D2[p] * dz2_inv; - pSPARC->D2_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_12 d/dx(df/dy) - pSPARC->D2_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // 2*T_13 d/dx(df/dz) - pSPARC->D2_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // 2*T_23 d/dy(df/dz) - pSPARC->D1_stencil_coeffs_xy[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dy_inv; // d/dx(2*T_12 df/dy) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_yx[p] = 2 * pSPARC->lapcT[1] * pSPARC->FDweights_D1[p] * dx_inv; // d/dy(2*T_12 df/dx) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_xz[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dz_inv; // d/dx(2*T_13 df/dz) used in d/dx(2*T_12 df/dy + 2*T_13 df/dz) - pSPARC->D1_stencil_coeffs_zx[p] = 2 * pSPARC->lapcT[2] * pSPARC->FDweights_D1[p] * dx_inv; // d/dz(2*T_13 df/dx) used in d/dz(2*T_13 df/dz + 2*T_23 df/dy) - pSPARC->D1_stencil_coeffs_yz[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dz_inv; // d/dy(2*T_23 df/dz) used in d/dy(2*T_12 df/dx + 2*T_23 df/dz) - pSPARC->D1_stencil_coeffs_zy[p] = 2 * pSPARC->lapcT[5] * pSPARC->FDweights_D1[p] * dy_inv; // d/dz(2*T_23 df/dy) used in d/dz(2*T_12 df/dx + 2*T_23 df/dy) - } - } - - // maximum eigenvalue of -0.5 * Lap (only with periodic boundary conditions) - if(pSPARC->cell_typ == 0) { -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - pSPARC->MaxEigVal_mhalfLap = pSPARC->D2_stencil_coeffs_x[0] - + pSPARC->D2_stencil_coeffs_y[0] - + pSPARC->D2_stencil_coeffs_z[0]; - double scal_x, scal_y, scal_z; - scal_x = (pSPARC->Nx - pSPARC->Nx % 2) / (double) pSPARC->Nx; - scal_y = (pSPARC->Ny - pSPARC->Ny % 2) / (double) pSPARC->Ny; - scal_z = (pSPARC->Nz - pSPARC->Nz % 2) / (double) pSPARC->Nz; - for (int p = 1; p < FDn + 1; p++) { - pSPARC->MaxEigVal_mhalfLap += 2.0 * (pSPARC->D2_stencil_coeffs_x[p] * cos(M_PI*p*scal_x) - + pSPARC->D2_stencil_coeffs_y[p] * cos(M_PI*p*scal_y) - + pSPARC->D2_stencil_coeffs_z[p] * cos(M_PI*p*scal_z)); - } - pSPARC->MaxEigVal_mhalfLap *= -0.5; -#ifdef DEBUG - t2 = MPI_Wtime(); - if (!rank) printf("Max eigenvalue of -0.5*Lap is %.13f, time taken: %.3f ms\n", - pSPARC->MaxEigVal_mhalfLap, (t2-t1)*1e3); -#endif - } - - double h_eff = 0.0; - if (fabs(pSPARC->delta_x - pSPARC->delta_y) < 1E-12 && - fabs(pSPARC->delta_y - pSPARC->delta_z) < 1E-12) { - h_eff = pSPARC->delta_x; - } else { - // find effective mesh s.t. it has same spectral width - h_eff = sqrt(3.0 / (dx2_inv + dy2_inv + dz2_inv)); - } - - // find Chebyshev polynomial degree based on max eigenvalue (spectral width) - if (pSPARC->ChebDegree < 0) { - pSPARC->ChebDegree = Mesh2ChebDegree(h_eff); -#ifdef DEBUG - if (!rank && h_eff < 0.1) { - printf("WARNING: for mesh less than 0.1, the default Chebyshev polynomial degree might not be enought!\n"); - } - if (!rank) printf("h_eff = %.2f, npl = %d\n", h_eff,pSPARC->ChebDegree); -#endif - } else { -#ifdef DEBUG - if (!rank) printf("Chebyshev polynomial degree (provided by user): npl = %d\n",pSPARC->ChebDegree); -#endif - } - - // default Kerker tolerance - if (pSPARC->TOL_PRECOND < 0.0) { // kerker tol not provided by user - pSPARC->TOL_PRECOND = (h_eff * h_eff) * 1e-3; - } - - - // re-calculate k-point grid - Calculate_kpoints(pSPARC); - - // re-calculate local k-points array - if (pSPARC->Nkpts >= 1 && pSPARC->kptcomm_index != -1) { - if (pSPARC->sqAmbientFlag == 0 && pSPARC->sqHighTFlag == 0 && pSPARC->OFDFTFlag == 0) { - Calculate_local_kpoints(pSPARC); - } - } - -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // re-calculate pseudocharge density cutoff ("rb") - Calculate_PseudochargeCutoff(pSPARC); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf("Calculating rb for all atom types took %.3f ms\n",(t2-t1)*1000); -#endif - - - // write reinitialized parameters into output file - if (rank == 0) { - write_output_reinit_NPT(pSPARC); - } - -} - - -/* -@ brief: calculate Hamiltonian of the NPT system. -*/ -void hamiltonian_NPT_NH(SPARC_OBJ *pSPARC){ - double kineticBaro, kineticTher, potentialBaro, potentialTher; - double hamiltonian; - int i; - - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - - hamiltonian = pSPARC->KE + pSPARC->Etot; - kineticBaro = pow(pSPARC->vlogv, 2.0) * pSPARC->NPT_NHbmass * 0.5; - kineticTher = 0.0; - for (i = 0; i < pSPARC->NPT_NHnnos; i++){ - kineticTher += pow(pSPARC->vlogs[i], 2.0) * pSPARC->NPT_NHqmass[i] * 0.5; - } - double ktemp; - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x * pSPARC->range_y * pSPARC->range_z; - ktemp = pSPARC->kB * pSPARC->thermos_T; - potentialBaro = pSPARC->prtarget * pSPARC->volumeCell; - potentialTher = (double)pSPARC->dof * ktemp * pSPARC->xlogs[0]; - for (i = 1; i < pSPARC->NPT_NHnnos; i++){ - potentialTher += ktemp * pSPARC->xlogs[i]; - } - hamiltonian += kineticBaro + kineticTher + potentialBaro + potentialTher; - pSPARC->Hamiltonian_NPT_NH = hamiltonian; - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", kineticBaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", kineticTher); - printf("barostat potential energy (Ha) : %12.9f\n", potentialBaro); - printf("thermostat potential energy (Ha): %12.9f\n", potentialTher); - printf("Hamiltonian (Ha) : %12.9f\n", hamiltonian); - } -} - - - -/* -@ brief function to perform NPT MD simulation with Nose-Poincare, wherein number of particles, pressure and temperature are kept constant -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -*/ -void NPT_NP (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPT_NP timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -@ brief function to perform NPH MD simulation , wherein number of particles, pressure and enthalpy are kept constant -This is same as NPT_NP wherein Mass of thermostat is zero. So same functions are used. -Reference: Hernández, E. "Metric-tensor flexible-cell algorithm for isothermal–isobaric molecular dynamics simulations." -The Journal of Chemical Physics 115, no. 22 (2001): 10282-10290. -Reference: Souza, Ivo, and JoséLuís Martins. "Metric tensor as the dynamical variable for variable-cell-shape molecular dynamics." -Physical Review B 55.14 (1997): 8733. -*/ -void NPH (SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Bcast(&pSPARC->stress, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - MPI_Bcast(&pSPARC->stress_i, 9, MPI_DOUBLE, 0, MPI_COMM_WORLD); - - pSPARC->NPT_NP_qmass = 0; - //NPT_NPH_main routine - NPT_NPH_main(pSPARC); - - // Reinitialize mesh size and related variables after changing size of cell - reinitialize_mesh_NPT(pSPARC); - - // Charge extrapolation (for better rho_guess) - elecDensExtrapolation(pSPARC); - // Check position of atom near the boundary and apply wraparound in case of PBC, otherwise show error if the atom is too close to the boundary for bounded domain - Check_atomlocation(pSPARC); - // Compute DFT energy and forces by solving Kohn-Sham eigenvalue problem - Calculate_Properties(pSPARC); - //Calculate_electronicGroundState(pSPARC); - pSPARC->elecgs_Count++; - #ifdef DEBUG - if (!rank) printf("\nend NPH timestep %d\n", pSPARC->MDCount + 1); - #endif -} - - -/* -Computes transpose of a matrix and adds it to the original matrix -*/ -void transpose_and_add(double *matrix1, int flag){ - - //Pure transpose - if (flag==0){ - double tmp; - // Swap (0,1) with (1,0) - tmp = matrix1[1]; matrix1[1] = matrix1[3]; matrix1[3] = tmp; - // Swap (0,2) with (2,0) - tmp = matrix1[2]; matrix1[2] = matrix1[6]; matrix1[6] = tmp; - // Swap (1,2) with (2,1) - tmp = matrix1[5]; matrix1[5] = matrix1[7]; matrix1[7] = tmp; - } - - //performs matrix1 = matrix1 + transpose(matrix1) - else if (flag==1){ - // Diagonals: m[i][i] = m[i][i] + m[i][i] - matrix1[0] *= 2.0; matrix1[4] *= 2.0; matrix1[8] *= 2.0; - - // Off-diagonals: sum then assign to both sides - double s01 = matrix1[1] + matrix1[3]; // (0,1) + (1,0) - double s02 = matrix1[2] + matrix1[6]; // (0,2) + (2,0) - double s12 = matrix1[5] + matrix1[7]; // (1,2) + (2,1) - - matrix1[1] = matrix1[3] = s01; - matrix1[2] = matrix1[6] = s02; - matrix1[5] = matrix1[7] = s12; - } -} - -/* -Computes: full_lattice (lattice vectors scaled by LATVEC SCALE), and corresponding: reciprocal_lattice, metric_tensor, reciprocal_matric_tensor, initialLatVecAngles, rotation_matrix -*/ -void fetch_MD_cell_ingredients(SPARC_OBJ *pSPARC){ - - double old_cell[9]; double new_cell[9]; - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - - //Compute Cell lattice vectors (scaled by LATVEC scale) - int row, col; - for (row = 0; row < 3; row++) { - pSPARC->full_lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - pSPARC->full_lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - pSPARC->full_lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - //Compute metric_tensor (G) in real-space (not reciprocal space) - cblas_dgemm(CblasRowMajor,CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->full_lattice, 3, 0.0, pSPARC->metric_tensor, 3); - - - // Rotated cell, such that the lattice vectors are: LatVec1 = (a,0,0); LatVec2 = (b1, b2, 0); LatVec3 = (c1,c2,c3) - new_cell[0] = sqrt(pSPARC->metric_tensor[0]); - new_cell[1] = 0; - new_cell[2] = 0; - - new_cell[3] = pSPARC->metric_tensor[3]/sqrt(metric_tensor[0]); - new_cell[4] = sqrt(pSPARC->metric_tensor[4]- pSPARC->metric_tensor[3]*pSPARC->metric_tensor[3])/pSPARC->metric_tensor[0]; - new_cell[5] = 0; - - new_cell[6] = pSPARC->metric_tensor[6]/sqrt(pSPARC->metric_tensor[0]); - new_cell[7] = (pSPARC->metric_tensor[0]*pSPARC->metric_tensor[7] - pSPARC->metric_tensor[3]*pSPARC->metric_tensor[6])/sqrt(pSPARC->metric_tensor[0]*pSPARC->metric_tensor[0]*pSPARC->metric_tensor[4] - pSPARC->metric_tensor[0]*pSPARC->metric_tensor[3]*pSPARC->metric_tensor[3]); - new_cell[8] = sqrt(pSPARC->metric_tensor[8] - new_cell[6] * new_cell[6] - new_cell[7] * new_cell[7]) - - for (int i = 0; i<9; i++){ - old_cell[i] = pSPARC->full_lattice[i] - } - - // Angles between cell lattice vectors (useful in case of restricting lattice vectors rotation in NPT_NP and NPH simulations) - pSPARC->initialLatVecAngles[0] = cblas_ddot(3,&lattice1[3], 1.0, &lattice1[6],1.0 )/(pSPARC->range_y*pSPARC->range_z); // cos_alpha - pSPARC->initialLatVecAngles[1] = cblas_ddot(3,&lattice1[0], 1.0, &lattice1[6],1.0 )/(pSPARC->range_x*pSPARC->range_z); // cos_beta - pSPARC->initialLatVecAngles[2] = cblas_ddot(3,&lattice1[0], 1.0, &lattice1[3],1.0 )/(pSPARC->range_x*pSPARC->range_y); // cos_gamma - - // Calculate the inverse of lattice-vector - double U[9], S[3], VT[9], superb[2], temp_mat[9] - double S_inv[9] = {0} - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', 3,3,old_cell,3,S,U,3,VT,3,superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - // Note that since lattice1 is rowMajor, reciprocal_lattice1 is columnMajor - // i.e. the reciprocal lattice vectors (of lattice1) are stored column-wise - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, VT, 3, S_inv, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, temp_mat, 3, U, 3, 0.0, pSPRAC->reciprocal_lattice, 3); - - //Rotation_matrix = reciprocal_lattice1.T*new_cell.T as we want: new_cell@Rotation_matrix = old_cell; - cblas_dgemm(CblasRowMajor, CblasTrans, CblasTrans, 3, 3, 3, 1.0, pSPRAC->reciprocal_lattice, 3, new_cell, 3, 0.0, pSPARC->rotation_matrix, 3); - - // Now computing reciprocal metric tensor, - cblas_dgemm(cblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPRAC->reciprocal_lattice, 3, pSPRAC->reciprocal_lattice, 3, 0.0, pSPARC->reciprocal_metric_tensor, 3); - - - //TODO: Update cell volume - //TODO: Update Jacbdet - //TODO: Update LatVec - //TODO: Update LatUvec - - //Computing velocity of lattice vectors - double temp_mat_2[9] = {0.0}; double temp_mat_3[9]; - - for (int iu1 = 0; iu1 < 9; iu1++){ - temp_mat_3[iu1] = pSPARC->Pm_metric_tensor; - } - - cblas_dscal(9, pSPARC->SNOSE[2] / ( pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell ), temp_mat_3, 1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3, temp_mat_3, 3, 0.0, temp_mat_2, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_2, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_3, 3); - - for (int iu1 = 0; iu1 < 9; iu1++){ - temp_mat_2[iu1] = 0.0; - pSPARC->lattice_avg_velo[iu1] = 0.0; - } - - temp_mat_2[0] = temp_mat_3[0] / (2.0 * new_cell[0]); - temp_mat_2[1] = 0.0; - temp_mat_2[2] = 0.0; - - temp_mat_2[3] = (temp_mat_3[3] - temp_mat_2[0] * new_cell[3]) / new_cell[0]; - temp_mat_2[4] = (0.5 * temp_mat_3[4] - temp_mat_2[3] * new_cell[3]) / new_cell[4]; - temp_mat_2[5] = 0.0; - - temp_mat_2[6] = (temp_mat_3[6] - temp_mat_2[0] * new_cell[6]) / new_cell[0]; - temp_mat_2[7] = (temp_mat_3[7] - temp_mat_2[6] * new_cell[3] - temp_mat_2[3] * new_cell[6] - temp_mat_2[4] * new_cell[7]) / new_cell[4]; - temp_mat_2[8] = (0.5 * temp_mat_3[8] - temp_mat_2[6] * new_cell[6] - temp_mat_2[7] * new_cell[7]) / new_cell[8]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->rotation_matrix , 3, temp_mat_2, 3, 0.0, pSPARC->lattice_avg_velo, 3); - -} - -void Calculate_Ionic_particles_Kinetic_energy(SPARC_OBJ *pSPARC){ - double vec1[3]; - int count = 0; - - pSPARC->KE = 0.0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - cblas_dgemv(CblasRowMajor, CblasNoTrans,3,3,1.0,pSPARC->reciprocal_metric_tensor,3,&pSPARC->Pm_ion[count*3],1,0.0,vec1,1); - pSPARC->KE += cblas_ddot(3,vec1,1, &pSPARC->Pm_ion[count*3],1)/pSPARC->Mass[ityp]; - count ++; - } - } - pSPARC->KE = 0.5*pSPARC->KE/(pSPARC->SNOSE[0]*pSPARC->SNOSE[0]); - double temperature = 2.0*pSPARC->KE/(pSPARC->dof*pSPARC->kB) -} - - -void Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(SPARC_OBJ *pSPARC){ - double kinetic_stress[9] = {0.0}; - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_vel[count*3] = (pSPARC->reciprocal_metric_tensor[0] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[1] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[2] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count*3+1] = (pSPARC->reciprocal_metric_tensor[3] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[4] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[5] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count*3+2] = (pSPARC->reciprocal_metric_tensor[6] * pSPARC->Pm_ion[count*3] + pSPARC->reciprocal_metric_tensor[7] * pSPARC->Pm_ion[count*3+1] + pSPARC->reciprocal_metric_tensor[8] * pSPARC->Pm_ion[count*3+2]) / pSPARC->Mass[ityp]; - - } - } - - int count = 0; - for(int ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(int atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - kinetic_stress[0] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3]; - kinetic_stress[1] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+1]; - kinetic_stress[2] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3] * pSPARC->ion_vel[count*3+2]; - kinetic_stress[4] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+1]; - kinetic_stress[5] += pSPARC->Mass[ityp] * pSPARC->ion_vel[count*3+1] * pSPARC->ion_vel[count*3+2]; - count++; - } - } - - kinetic_stress[3] = kinetic_stress[1]; - kinetic_stress[6] = kinetic_stress[2]; - kinetic_stress[7] = kinetic_stress[5]; - - cblas_dscal(9, 0.5 / (pSPARC->SNOSE[0] * pSPARC->SNOSE[0]), kinetic_stress, 1); - - for (int its1 = 0; its1<9; its1++){ - pSPARC->total_internal_stress[its1] = ( kinetic_stress[its1] - pSPARC->internal_stress - pSPARC->constraint_stress) - } - - cblas_dscal(9, 1.0 / (pSPARC->volumeCell), pSPARC->total_internal_stress, 1); - - pSPARC->internal_pressure = 2.0 / 3.0 * cblas_ddot(9, pSPARC->total_internal_stress, 1, pSPARC->metric_tensor, 1); - -} - -/* - @ brief: Does several things: - -initialize momentum of barostat variables Pm, and calculate Hamiltonian of the system (Eqn 10 in Hernandez paper) - -update momentum of thermostat, barostat variables and ions in a half step (Eqns. 18g, 18h, 18i) - -update momentum - -*/ -void NPT_NPH_main(SPARC_OBJ *pSPARC){ - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - double ktemp; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; double temp_mat_a[9]; double temp_mat_b[9]; double temp_Pm_mat[9]; - double internal_stress_cartesian[9]; double internal_stress_fractional[9]; - - pSPARC->ionic_forces_fractional = (double *)malloc(pSPARC->n_atom*3 * sizeof(double) ); - - //Initialize some useful constants - double baro_const1 = pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; // M_G*det(G) in the Hernandez paper - double baro_const2 = baro_const1 / pSPARC->SNOSE[2]; - double baro_const3 = 1.0 / baro_const1; - - - // ------------------------------------- BEGIN: Calculating Hamiltonian (Eqn 10a)----------------------------------// - // Calculating momentum of ions - int ityp, atm; - int count = 0; - cblas_dscal(pSPARC->n_atom*3,pSPARC->SNOSE[2],pSPARC->ion_vel,1); - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - cblas_dgemv(CblasRowMajor,CblasNoTrans,3,3,pSPARC->Mass[ityp],pSPARC->metric_tensor,3,&pSPARC->ion_vel[count*3],1,0.0,&pSPARC->Pm_ion[count*3],1) - count ++; - } - } - - - // Calculating kinetic energy of ions - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - - // Calculating thermostat energies - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - ktemp = pSPARC->kB * pSPARC->thermos_T; - pSPARC->Uther = (double)pSPARC->dof * log(pSPARC->SNOSE[0]) * ktemp; //Entropic - - - // Calculating barostat energies - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 3, 1.0, pSPARC->full_lattice, 3, pSPARC->lattice_avg_velo, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - transpose_and_add(pSPARC->Pm_metric_tensor,1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3, pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->Pm_metric_tensor, 3); - cblas_dscal(pSPARC->n_atom*3,baro_const1,pSPARC->Pm_metric_tensor,1); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3, pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9,temp_mat_a, 1, temp_mat_b,1);//Kinetic - pSPARC->Ubaro = pSPARC->pr_external * pSPARC->volumeCell; //Potential - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, pSPARC->volumeCell, pSPARC->external_stress_cartesian, 3, pSPARC->reciprocal_metric_tensor, 3, 0.0, pSPARC->external_stress_lattice, 3); - pSPARC->Ubaro += 0.5*cblas_ddot(9,pSPARC->external_stress_lattice,1,pSPARC->metric_tensor,1) - - double sumAllHamilTerms = pSPARC->Etot; - sumAllHamilTerms += pSPARC->KE + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - if ((pSPARC->MDCount == 1) && (pSPARC->RestartFlag != 1)) { - pSPARC->init_Hamil_NPT_NP = sumAllHamilTerms; - } - pSPARC->Hamiltonian_NPT_NP = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); - #ifdef DEBUG - if (rank == 0) { - printf("\n"); - printf("rank %d", rank); - printf("ENERGY of time step %d\n", pSPARC->MDCount + 1); - printf("kinetic energy (Ha) : %12.9f\n", pSPARC->KE); - printf("potential energy (Ha) : %12.9f\n", pSPARC->Etot); - printf("barostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kbaro); - printf("thermostat kinetic energy (Ha) : %12.9f\n", pSPARC->Kther); - printf("barostat potential energy (Ha) : %12.9f\n", pSPARC->Ubaro); - printf("thermostat potential energy (Ha): %12.9f\n", pSPARC->Uther); - printf("Sum of all energy terms (Ha) : %12.9f\n", sumAllHamilTerms); - printf("Hamiltonian (Ha) : %12.9f\n", pSPARC->Hamiltonian_NPT_NP); - } - #endif - // ------------------------------------- END: Calculating Hamiltonian (Eqn 10a)----------------------------------// - - - // ------------------------------------- BEGIN: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - double Sa; - // bring the momenta of the thermostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This corresponds Eqn. 18G in the Hernandez paper (Skip this step if doing NPH since thermostat mass = 0) - if (pSPARC->NPT_NP_qmass > 0){ - ktemp = pSPARC->kB * pSPARC->thermos_T; - Sa = (pSPARC->KE - pSPARC->Etot - pSPARC->dof*ktemp * (log(pSPARC->SNOSE[0]) + 1) - pSPARC->Kbaro - pSPARC->Ubaro - pSPARC->Kther + pSPARC->init_Hamil_NPT_NP) / pSPARC->NPT_NP_qmass; - pSPARC->SNOSE[1] += Sa * pSPARC->MD_dt / 2.0; - - // Update the kinetic energy of the thermostat - pSPARC->Kther = 0.5 * pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1] * pSPARC->SNOSE[1]; //Kinetic - } - #ifdef DEBUG - if (rank == 0) { - printf("Sa is %12.9f\n", Sa); - printf("SNOSE[1] in the 1st half step is %12.9f\n", pSPARC->SNOSE[1]); - } - #endif - - - // bring the momenta of the barostat variable in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds Eqn. 18h in the Hernandez paper - internal_stress_cartesian[0] = pSPARC->stress[0]; internal_stress[4] = pSPARC->stress[3]; internal_stress[8] = pSPARC->stress[5]; - internal_stress_cartesian[1] = pSPARC->stress[1]; internal_stress[2] = pSPARC->stress[2]; internal_stress[3] = pSPARC->stress[1]; - internal_stress_cartesian[5] = pSPARC->stress[4]; internal_stress[6] = pSPARC->stress[2]; internal_stress[7] = pSPARC->stress[4]; - - //temp_mat_a is a copy of reciprocal lattice vectors (columnMajor orientation: so reciprocal lattice vectors are columns) - for (int itma1 = 0; itma1<9; itma1++){ - temp_mat_a[itma1] = pSPARC->reciprocal_lattice[itma1]; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, internal_stress_cartesian, 3, temp_mat_a, 3, 0.0, temp_mat_b,3 ); - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, 3, 3, 3, 0.5, temp_mat_a, 3, temp_mat_b, 3, 0.0, internal_stress_fractional,3 ); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_mat_a, 3,pSPARC->Pm_metric_tensor, 3, 0.0, temp_mat_b, 3); - - for (int ix1 = 0; ix1<9; ix1++){ - temp_Pm_mat[ix1] = pSPARC->Pm_metric_tensor[ix1]; - } - - // Eqn. 18h Hernandez paper - for (int ih18 = 0; ih18<9; ih18++){ - temp_mat[ih18] = internal_stress_fractional[ih18] - pSPARC->kinetic_stress[ih18] + temp_mat_b[ih18]; - temp_mat[ih18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ih18] + 0.5*pSPARC->external_stress_lattice[ih18]; - pSPARC->Pm_metric_tensor[ih18] -= 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ih18]; - } - - if (pSPARC->NPT_NP_ANGLES == 0){ - compute_constraint_stress(pSPARC); - } - - for (int ih18 = 0; ih18<9; ih18++){ - temp_mat[ih18] = internal_stress_fractional[ih18] + pSPARC->constraint_stress[ih18] - pSPARC->kinetic_stress[ih18] + temp_mat_b[ih18]; - temp_mat[ih18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ih18] + 0.5*pSPARC->external_stress_lattice[ih18]; - pSPARC->Pm_metric_tensor[ih18] = temp_Pm_mat[ih18] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ih18]; - } - - if (ISIF == 10){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - - if (ISIF == 11){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, pSPARC->Pm_metric_tensor, 3,pSPARC->metric_tensor, 3, 0.0, temp_mat_a, 3); - //Since these are 3x3 matrix, transposing without for loop (for avoiding loop overhead cost) - temp_mat_b[0] = temp_mat_a[0]; temp_mat_b[4] = temp_mat_a[4]; temp_mat_b[8] = temp_mat_a[8]; - temp_mat_b[1] = temp_mat_a[3]; temp_mat_b[2] = temp_mat_a[6]; temp_mat_b[5] = temp_mat_a[7]; - temp_mat_b[3] = temp_mat_a[1]; temp_mat_b[6] = temp_mat_a[2]; temp_mat_b[7] = temp_mat_a[5]; - - //Update the kinetic energy of the barostat - pSPARC->Kbaro = 0.5 * baro_const1 * cblas_ddot(9,temp_mat_a, 1, temp_mat_b,1);//Kinetic - - - // bring the momenta of the Ionic particles in time-sync with the positions (since mometa are delayed by dt/2) - // This setup corresponds to Eqn. 18i in Hernandez paper - double thermo_const0 = pSPARC->MD_dt*pSPARC->SNOSE[0] / 2.0; - for(int natm1 = 0; natm1 < pSPARC->n_atom; natm1++){ - pSPARC->ionic_forces_fractional[natm1*3] = (pSPARC->full_lattice[0] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[1] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[2] * pSPARC->forces[natm1*3+2]); - pSPARC->ionic_forces_fractional[natm1*3+1] = (pSPARC->full_lattice[3] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[4] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[5] * pSPARC->forces[natm1*3+2]); - pSPARC->ionic_forces_fractional[natm1*3+2] = (pSPARC->full_lattice[6] * pSPARC->forces[natm1*3] + pSPARC->full_lattice[7] * pSPARC->forces[natm1*3+1] + pSPARC->full_lattice[8] * pSPARC->forces[natm1*3+2]); - - pSPARC->Pm_ion[natm1*3] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3]; - pSPARC->Pm_ion[natm1*3+1] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+1]; - pSPARC->Pm_ion[natm1*3+2] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+2]; - } - - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); - - //Now write Intenal pressure, external pressure to a file - - // ------------------------------------- END: Updating Momenta by half step (Eqns. 18g, 18h, 18i)----------------------------------// - - - //Calculate/Update total energy (Hamiltonian) - sumAllHamilTerms = pSPARC->KE + pSPARC->Etot + pSPARC->Kther + pSPARC->Uther + pSPARC->Kbaro + pSPARC->Ubaro; - double constant_of_motion = pSPARC->SNOSE[0] * (sumAllHamilTerms - pSPARC->init_Hamil_NPT_NP); - //Optionall write all individual energy contributions to the Hamiltonian to an output file - - - // ------------------------------------- BEGIN: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - // Now we update/Step-up the momenta of the Ionic particles by dt/2 - // This setup corresponds to Eqn. 18a in Hernandez paper - for(int natm1 = 0; natm1 < pSPARC->n_atom; natm1++){ - pSPARC->Pm_ion[natm1*3] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3]; - pSPARC->Pm_ion[natm1*3+1] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+1]; - pSPARC->Pm_ion[natm1*3+2] += thermo_const0 * pSPARC->ionic_forces_fractional[natm1*3+2]; - } - - //Update the velocities of Ionic particles, calculate the kinetic stress and internal pressure - Update_ion_vel_Calculate_Kinetic_stress_and_total_internal_pressure(pSPARC); - - //Update the kinetic energy of the Ionic particles - Calculate_Ionic_particles_Kinetic_energy(pSPARC); - - - // Now we update/Step-up the momenta of the barostat by dt/2 - // This setup corresponds to Eqn. 18b in the Hernandez paper - // This needs to be solved iteratively - Update_metric_tensor_momenta_iteratively_half_step(pSPARC); - - //Now impose the constraints on it - if (ISIF == 10){ - pSPARC->Pm_metric_tensor[8] = 0; - pSPARC->Pm_metric_tensor[7] = 0; - pSPARC->Pm_metric_tensor[6] = 0; - pSPARC->Pm_metric_tensor[5] = 0; - pSPARC->Pm_metric_tensor[2] = 0; - } - - if (ISIF == 11){ - pSPARC->Pm_metric_tensor[0] = 0; - pSPARC->Pm_metric_tensor[4] = 0; - } - - - // Now we update/Step-up the momenta of the thermostat by dt/2 - // This setup corresponds to Eqn. 18c in the Hernandez paper - // Skip this step if doing NPH ensemble - if (pSPARC->NPT_NP_qmass > 0){ - double factor; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - factor = 0.5 * pSPARC->MD_dt *( pSPARC->dof * ktemp * (log(pSPARC->SNOSE[0])+1) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP ) - pSPARC->NPT_NP_qmass * pSPARC->SNOSE[1]; - - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor*pSPARC->MD_dt/pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - exit(EXIT_FAILURE); - } - - pSPARC->SNOSE[1] = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("Sv_NPT_NP in the 2nd half step is %12.9f\n", pSPARC->Sv_NPT_NP); - #endif - } - - - // Now we update/Step-up the Position of the thermostat by dt/2 - // This setup corresponds to Eqn. 18d in the Hernandez paper - double S_new; double S_temp; - int TimeIter = 0; - if (pSPARC->NPT_NP_qmass > 0){ // This gets executes when running NPT ensemble - S_temp = pSPARC->SNOSE[0]; - - while (1) { - S_new = pSPARC->SNOSE[0] + 0.5 * pSPARC->MD_dt * (pSPARC->SNOSE[0] + S_temp) * pSPARC->SNOSE[1]; - if (fabs(S_temp-S_new) < 1e-7) { - break; - } - S_temp = S_new; - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], - new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); - printf("Reminder The themostat position SNOSE[0] does not converge to %e tolerance in %d timesteps : stopping\n", 1e-7, pSPARC->maxTimeIter ); - exit(1); - } - } - #ifdef DEBUG - if (rank == 0) - printf("S_temp is %12.9f\n", S_temp); - #endif - } - else{ // This gets executes when running NPH ensemble - pSPARC->SNOSE[0] = 1.0; - pSPARC->SNOSE[1] = 0.0; - } - - // ------------------------------------- END: Updating Momenta by second half step (Eqns. 18a, 18b, 18c) - // END: And updating the position variable of the themostat if doing NPT_NP emsemble (Eqn. 18d) ----------------------------------// - - - - // ------------------------------------- BEGIN: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // And updating the atomic positions (Eqn. 18f), and restoring ionic velocties ----------------------------// - Update_metric_tensor_components_iteratively_full_step(pSPARC, S_new); - - //Update cell parameters: lattice vectors, reciprocal lattice vectors, volume of the cell, reciprocal metric tensor, cell lattice velocities using the updated metric tensor - fetch_MD_cell_ingredients(pSPARC); - - //Update atomic positions and restore ionic velocities - int count = 0; - int atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = (pSPARC->atom_pos[count * 3]) * scalex + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3]/S_new); // - pSPARC->atom_pos[count * 3 + 1] = (pSPARC->atom_pos[count * 3 + 1]) * scaley + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 1]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 1]/S_new); // - pSPARC->atom_pos[count * 3 + 2] = (pSPARC->atom_pos[count * 3 + 2]) * scalez + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 2]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 2]/S_new); // - pSPARC->ion_vel[count * 3] /= pSPARC->SNOSE[0]; - pSPARC->ion_vel[count * 3 + 1] /= pSPARC->SNOSE[0]; - pSPARC->ion_vel[count * 3 + 2] /= pSPARC->SNOSE[0]; - count ++; - } - - if (pSPARC->NPT_NP_qmass > 0){ - pSPARC->SNOSE[2] = pSPARC->SNOSE[0]; - pSPARC->SNOSE[0] = S_new; - } - // ------------------------------------- END: Updating Components of the metric tensor (Eqn. 18e)----------------------------------// - // END:And updating the atomic positions (Eqn. 18f), and restoring ionic velocties --------------------------// - - -} - - - - -void compute_constraint_stress(SPARC_OBJ *pSPARC){ - - //Initialize some useful constants - double a_norm; double b_norm; double c_norm; - double da_dt_norm; double db_dt_norm; double dc_dt_norm; - double baro_const4; double thermo_const1; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double constraint_velocity[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - a_norm = sqrt(pSPARC->full_lattice[0] * pSPARC->full_lattice[0] + pSPARC->full_lattice[1] * pSPARC->full_lattice[1] + pSPARC->full_lattice[2] * pSPARC->full_lattice[2]); - b_norm = sqrt(pSPARC->full_lattice[3] * pSPARC->full_lattice[3] + pSPARC->full_lattice[4] * pSPARC->full_lattice[4] + pSPARC->full_lattice[5] * pSPARC->full_lattice[5]); - c_norm = sqrt(pSPARC->full_lattice[6] * pSPARC->full_lattice[6] + pSPARC->full_lattice[7] * pSPARC->full_lattice[7] + pSPARC->full_lattice[8] * pSPARC->full_lattice[8]); - - baro_const4 = pSPARC->SNOSE[0]/(pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - - da_dt_norm = baro_const4 * gpig[0] / (2.0 * a_norm); - db_dt_norm = baro_const4 * gpig[4] / (2.0 * b_norm); - dc_dt_norm = baro_const4 * gpig[8] / (2.0 * c_norm); - - // Cell vectors are constrained to ISOTROPIC scaling; and all angles between lattice vectors are FIXED - if (ISIF == 8){ - gpig[0] = (gpig[0] + gpig[4] + gpig[8]) / 3; - gpig[4] = gpig[0]; - gpig[8] = gpig[0]; - } - - // |a| = |b| and |c| can vary independently; and all angles between lattice vectors are FIXED - else if (ISIF == 9){ - gpig[0] = (gpig[0] + gpig[4]) / 2; - gpig[4] = gpig[0]; - } - - // Only |a| and |b| varies, no changes in third direction i.e |c| is fixed; and all angles between lattice vectors are FIXED - else if (ISIF == 10){ - gpig[8] = 0; - gpig[7] = 0; - gpig[6] = 0; - gpig[5] = 0; - gpig[2] = 0; - } - - // Only |c| varies, |a| and |b| are fixed; and all angles between lattice vectors are FIXED - else if (ISIF == 11){ - gpig[0] = 0; - gpig[4] = 0; - } - - constraint_velocity[0] = gpig[0] * baro_const4; - constraint_velocity[4] = gpig[4] * baro_const4; - constraint_velocity[8] = gpig[8] * baro_const4; - - constraint_velocity[1] = (da_dt_norm * b_norm + a_norm * db_dt_norm) / pSPARC->initialLatVecAngles[2]; - constraint_velocity[2] = (da_dt_norm * c_norm + a_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[1]; - constraint_velocity[5] = (db_dt_norm * c_norm + b_norm * dc_dt_norm) / pSPARC->initialLatVecAngles[0]; - - constraint_velocity[3] = constraint_velocity[1]; - constraint_velocity[6] = constraint_velocity[2]; - constraint_velocity[7] = constraint_velocity[5]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->reciprocal_metric_tensor, 3,constraint_velocity, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0/baro_const4, gpi, 3,pSPARC->reciprocal_metric_tensor, 3, 0.0, gpig, 3); - - thermo_const1 = 2.0 / (pSPARC->MD_dt * pSPARC->SNOSE[0]); - - // Calculating constraint stress - for (int intcs1 = 0; intcs1<9; intcs1++){ - pSPARC->constraint_stress[intcs1] = thermo_const1 * (pSPARC->Pm_metric_tensor[intcs1] - gpig[intcs1]); - pSPARC->Pm_metric_tensor[intcs1] = gpig[intcs1]; - } -} - - -void Update_metric_tensor_components_iteratively_full_step(SPARC_OBJ *pSPARC, double S_new){ - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-7; // tolerance criterion for checking convergence - double baro_const11 = 0.5 * pSPARC->MD_dt / (pSPARC->NPT_NP_bmass); - double baro_const6 = baro_const11 * pSPARC->SNOSE[0] / (pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const7; - double det_temp_metric_tensor; - double a_norm; double b_norm; double c_norm; - - //Initialize empty temporary matrices and vectors - double gpi[9]; double gpig[9]; double gpig_old[9]; - double temp_metric_tensor[9]; double new_metric_tensor[9]; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, pSPARC->metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,pSPARC->metric_tensor, 3, 0.0, gpig, 3); - - for (int mtt1 = 0; mtt1 < 9; mtt1++){ - temp_metric_tensor[mtt1] = pSPARC->metric_tensor[mtt1]; - gpig_old[mtt1] = gpig[mtt1]; - } - - while (1){ - - det_temp_metric_tensor = temp_metric_tensor[0] * (temp_metric_tensor[4] * temp_metric_tensor[8] - temp_metric_tensor[7] * temp_metric_tensor[5] ) - + temp_metric_tensor[1] * (temp_metric_tensor[5] * temp_metric_tensor[6] - temp_metric_tensor[3] * temp_metric_tensor[8] ) - + temp_metric_tensor[2] * (temp_metric_tensor[3] * temp_metric_tensor[7] - temp_metric_tensor[6] * temp_metric_tensor[4] ) ; - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, temp_metric_tensor, 3,pSPARC->Pm_metric_tensor, 3, 0.0, gpi, 3); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, gpi, 3,temp_metric_tensor, 3, 0.0, gpig, 3); - - baro_const7 = baro_const11 * S_new / det_temp_metric_tensor; - - for (int mtn = 0; mtn < 9; mtn++){ - new_metric_tensor[mtn] = pSPARC->metric_tensor[mtn] + baro_const6 * gpig_old[mtn] + baro_const7 * gpig[mtn]; - } - - converged = true; - for (int ic1 = 0; ic1 < 9; ic1++){ - if ( fabs(new_metric_tensor[ic1] - temp_metric_tensor[ic1]) > tolerance ){ - converged = false; - break; - } - } - - if (converged){ - break; - } else{ - cblas_dscal(9, 0.5 , new_metric_tensor, 1); - temp_metric_tensor = transpose_and_add(new_metric_tensor); - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_metric_tensor[row][0], - new_metric_tensor[row][1], new_metric_tensor[row][2]); - printf("Reminder The barostat components: metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - } - - if (ISIF == 7){ - if (ISIF == 8){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] + new_metric_tensor[8]) / 3.0; - new_metric_tensor[4] = new_metric_tensor[0]; - new_metric_tensor[8] = new_metric_tensor[0]; - } - - else if (ISIF == 9){ - new_metric_tensor[0] = ( new_metric_tensor[0] + new_metric_tensor[4] ) / 2.0; - new_metric_tensor[4] = new_metric_tensor[0]; - } - - a_norm = sqrt( new_metric_tensor[0]); - b_norm = sqrt( new_metric_tensor[4]); - c_norm = sqrt( new_metric_tensor[8]); - - new_metric_tensor[1] = a_norm * b_norm * pSPARC->initialLatVecAngles[2]; - new_metric_tensor[2] = a_norm * c_norm * pSPARC->initialLatVecAngles[1]; - new_metric_tensor[5] = b_norm * c_norm * pSPARC->initialLatVecAngles[0]; - - new_metric_tensor[3] = new_metric_tensor[1]; - new_metric_tensor[6] = new_metric_tensor[2]; - new_metric_tensor[7] = new_metric_tensor[5]; - - for (int mtt1 = 0; mtt1 < 9; mtt1++){ - temp_metric_tensor[mtt1] = new_metric_tensor[mtt1]; - } - } - - for (int mt1 = 0; mt1 < 9; mt1++){ - pSPARC->metric_tensor[mt1] = temp_metric_tensor[mt1]; - } -} - - - -void Update_metric_tensor_momenta_iteratively_half_step(SPARC_OBJ *pSPARC){ - - //Initialize some useful constants - bool converged; // determine whether the iteration converges or not - int TimeIter = 0; // current iteration count - const double tolerance = 1e-12; // tolerance criterion for checking convergence - double baro_const0 = 0.5 * (pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell); - double baro_const3 = 0.5 / baro_const0; - double baro_const5 = baro_const0 * pSPARC->NPT_NP_bmass * pSPARC->volumeCell * pSPARC->volumeCell; - - //Initialize empty temporary matrices and vectors - double temp_mat[9]; - double temp_mat_1[9]; double temp_mat_2[9]; double temp_mat_3[9]; - double temp_Pm_metric_tensor[9]; double new_Pm_metric_tensor[9] = {0.0}; - - - for (int itpmt1 = 0; itpmt1 < 9; itpmt1++){ - temp_Pm_metric_tensor[itpmt1] = pSPARC->Pm_metric_tensor[itpmt1]; - } - - // Now iteratively solve equation 18b (i.e. find the new momenta of the barostat at time t+dt/2) - while (1){ - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, baro_const3, - temp_Pm_metric_tensor, 3, - pSPARC->metric_tensor[0][0], 3, - 0.0, temp_mat_1, 3); - - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, 1.0, - matrix_1, 3, - temp_Pm_metric_tensor, 3, - 0.0, temp_mat_2, 3); - - - //Transpose - temp_mat_3[0] = temp_mat_1[0]; temp_mat_3[4] = temp_mat_1[4]; temp_mat_3[8] = temp_mat_1[8]; - temp_mat_3[1] = temp_mat_1[3]; temp_mat_3[2] = temp_mat_1[6]; temp_mat_3[5] = temp_mat_1[7]; - temp_mat_3[3] = temp_mat_1[1]; temp_mat_3[6] = temp_mat_1[2]; temp_mat_3[7] = temp_mat_1[5]; - - pSPARC->Kbaro = baro_const5 * cblas_ddot(9, temp_mat_1, 1, temp_mat_3, 1); - - // Eqn. 18b Hernandez paper - for (int ib18 = 0; ib18<9; ib18++){ - temp_mat[ib18] = internal_stress_fractional[ib18] - pSPARC->kinetic_stress[ib18] + temp_mat_2[ib18]; - temp_mat[ib18] += (0.5*pSPARC->pr_external * pSPARC->volumeCell - pSPARC->Kbaro) * pSPARC->reciprocal_metric_tensor[ib18] + 0.5*pSPARC->external_stress_lattice[ib18]; - new_Pm_metric_tensor[ib18] = pSPARC->Pm_metric_tensor[ib18] - 0.5 * pSPARC->MD_dt * pSPARC->SNOSE[0] * temp_mat[ib18]; - } - - cblas_dscal(9, 0.5 , new_Pm_metric_tensor, 1); - transpose_and_add(new_Pm_metric_tensor, 1); - - //Check convergence - converged = true; - for (int ic1 = 0; ic1 < 9; ic1++){ - if ( fabs(new_Pm_metric_tensor[ic1] - temp_Pm_metric_tensor[ic1]) > tolerance ){ - converged = false; - break; - } - } - - // if yes then break; else resolve - if (converged){ - break; - } else{ - for (int ic1 = 0; ic1 < 9; ic1++){ - temp_Pm_metric_tensor[ic1] = new_Pm_metric_tensor[ic1]; - } - } - - TimeIter++; - //it iteration count exceeds max iteration counts, exit - if (TimeIter > pSPARC->maxTimeIter){ - for(int row = 0; row < 3; row++) - printf("%15.7f %15.7f %15.7f\n",new_Pm_metric_tensor[row][0], - new_Pm_metric_tensor[row][1], new_Pm_metric_tensor[row][2]); - printf("Reminder The barostat momentum Pm_metric_tensor does not converge to %e tolerance in %d timesteps : stopping\n", tolerance, pSPARC->maxTimeIter ); - exit(1); - } - - } - - // As converged, update the metric tensor momenta - for (int c11 = 0; c11 < 9; c11++){ - pSPARC->Pm_metric_tensor[c11] = temp_Pm_metric_tensor[c11]; - } -} - - - - -void updateMomentum_FirstHalf(SPARC_OBJ *pSPARC) { - double ktemp; - double Ga1[3]; - double B[3]; - double Ga3[3]; - double PmA[3]; - - - - - - // update momentum of barostat variables in a half step - for (int i = 0; i < 3; i++){ - if (pSPARC->NPTscaleVecs[i] == 1) { - Ga1[i] = innerControlStress[i] * pSPARC->volumeCell / 2.0 / pSPARC->G_NPT_NP[i]; - B[i] = 1.0 / (pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) * pow(pSPARC->Pm_NPT_NP[i],2.0) * pSPARC->G_NPT_NP[i]; - Ga3[i] = (pSPARC->prtarget * pSPARC->volumeCell / 2.0 - pSPARC->Kbaro) / pSPARC->G_NPT_NP[i]; - PmA[i] = Ga1[i] + B[i] + Ga3[i]; - pSPARC->Pm_NPT_NP[i] -= pSPARC->MD_dt * pSPARC->S_NPT_NP / 2.0 * PmA[i]; - #ifdef DEBUG - if (rank == 0){ - // printf("pSPARC->pres is %12.9f, pSPARC->pres_i is %12.9f, pSPARC->volumeCell is %12.9f, pSPARC->G_NPT_NP[%d] is %12.9f\n", pSPARC->pres, pSPARC->pres_i, pSPARC->volumeCell, i, pSPARC->G_NPT_NP[i]); - printf("PmA[%d] is %12.9f\n", i, PmA[i]); - printf("pSPARC->Pm_NPT_NP[%d] in 1st half step is %12.9f\n", i, pSPARC->Pm_NPT_NP[i]); - } - #endif - } - } - // update momentum/mass of particles (reminder: not velocity!) in a step - int ityp, atm; - int count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->ion_accel[count * 3] = pSPARC->forces[count * 3] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 1] = pSPARC->forces[count * 3 + 1] / pSPARC->Mass[ityp]; - pSPARC->ion_accel[count * 3 + 2] = pSPARC->forces[count * 3 + 2] / pSPARC->Mass[ityp]; - pSPARC->ion_vel[count * 3] = pSPARC->ion_vel[count * 3] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3]; - pSPARC->ion_vel[count * 3 + 1] = pSPARC->ion_vel[count * 3 + 1] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3 + 1]; - pSPARC->ion_vel[count * 3 + 2] = pSPARC->ion_vel[count * 3 + 2] * pSPARC->S_NPT_NP + pSPARC->MD_dt * pSPARC->S_NPT_NP * pSPARC->ion_accel[count * 3 + 2]; - // for now they are not velocity! - count ++; - } - } -} - -/* - @ brief: update momentum of thermostat and barostat variables in the second half step -*/ -void updateMomentum_SecondHalf(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - double PmTmp[3], PmNew[3]; - int i; - for (i = 0; i < 3; i++){ - PmTmp[i] = pSPARC->Pm_NPT_NP[i]; - } - // update momentum of barostat variables in the second half time step - int judge = 0; - int timeIter = 0; - double G1[3], Gatmp1[3], Gatmp2[3], Gatmp3[3], PmAtmp[3]; - double KbaroTmp = 0; - - double diagElecStress[3], innerControlStress[3]; - diagElecStress[0] = pSPARC->stress[0] - pSPARC->stress_i[0]; - diagElecStress[1] = pSPARC->stress[3] - pSPARC->stress_i[3]; - diagElecStress[2] = pSPARC->stress[5] - pSPARC->stress_i[5]; - // innerControlStress is used for adding confinements on the scale of lattice vectors, such as |a|=|b|. - innerControlStress[0] = diagElecStress[0]; - innerControlStress[1] = diagElecStress[1]; - innerControlStress[2] = diagElecStress[2]; - if (pSPARC->NPTconstraintFlag == 1) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[1]) / 2; - innerControlStress[1] = innerControlStress[0]; - } else if (pSPARC->NPTconstraintFlag == 2) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[2]) / 2; - innerControlStress[2] = innerControlStress[0]; - } else if (pSPARC->NPTconstraintFlag == 3) { - innerControlStress[1] = (diagElecStress[1] + diagElecStress[2]) / 2; - innerControlStress[2] = innerControlStress[1]; - } else if (pSPARC->NPTconstraintFlag == 4) { - innerControlStress[0] = (diagElecStress[0] + diagElecStress[1] + diagElecStress[2]) / 3; - innerControlStress[1] = innerControlStress[0]; - innerControlStress[2] = innerControlStress[0]; - } - - while (judge == 0) { - timeIter++; - KbaroTmp = 0; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - G1[i] = 1 / (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) * PmTmp[i] * pSPARC->G_NPT_NP[i]; - KbaroTmp += (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) / 2 * pow(G1[i],2.0); - } - } - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - Gatmp1[i] = innerControlStress[i] * pSPARC->volumeCell / 2.0 / pSPARC->G_NPT_NP[i]; - Gatmp2[i] = G1[i] * PmTmp[i]; - Gatmp3[i] = (pSPARC->prtarget * pSPARC->volumeCell / 2.0 - KbaroTmp) / pSPARC->G_NPT_NP[i]; - PmAtmp[i] = Gatmp1[i] + Gatmp2[i] + Gatmp3[i]; - PmNew[i] = pSPARC->Pm_NPT_NP[i] - pSPARC->MD_dt / 2.0 * pSPARC->S_NPT_NP * PmAtmp[i]; - } - } - judge = 1; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - if (fabs(PmNew[i] - PmTmp[i]) > 1e-7){ - judge = 0; - } - PmTmp[i] = PmNew[i]; - } - } - if (timeIter > pSPARC->maxTimeIter){ - judge = 1; - if (rank == 0) - printf("Reminder: The barostat momentum Pm_NPT_NP does not converge in %d timesteps.\n", pSPARC->maxTimeIter); - } - } - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - pSPARC->Pm_NPT_NP[i] = PmTmp[i]; - #ifdef DEBUG - if (rank == 0) - printf("pSPARC->Pm_NPT_NP[%d] in 2nd half step is %12.9f\n", i, pSPARC->Pm_NPT_NP[i]); - #endif - } - } - - // update thermostat velocity in the second half time step - pSPARC->KE = 0.0; - int ityp, atm; - int count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - pSPARC->KE += 0.5 * pSPARC->Mass[ityp] * (pow(pSPARC->ion_vel[count * 3], 2.0) + pow(pSPARC->ion_vel[count * 3 + 1], 2.0) + pow(pSPARC->ion_vel[count * 3 + 2], 2.0)); - count ++; - } - } - pSPARC->KE /= pow(pSPARC->S_NPT_NP, 2.0); // from momentum/mass to true velocity - pSPARC->Kbaro = 0.0; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - G1[i] = 1.0 / (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) * PmTmp[i] * pSPARC->G_NPT_NP[i]; - pSPARC->Kbaro += (pSPARC->NPT_NP_bmass * pow(pSPARC->volumeCell, 2.0)) / 2.0 * pow(G1[i],2.0); - } - } - double factor; - double ktemp = pSPARC->kB * pSPARC->thermos_T; - factor = pSPARC->MD_dt / 2.0 * (pSPARC->dof*ktemp*(log(pSPARC->S_NPT_NP) + 1) - pSPARC->KE + pSPARC->Etot + pSPARC->Kbaro + pSPARC->Ubaro - pSPARC->init_Hamil_NPT_NP) - pSPARC->NPT_NP_qmass*pSPARC->Sv_NPT_NP; - #ifdef DEBUG - if (rank == 0) - printf("factor is %12.9f\n", factor); - #endif - if ((1.0 - factor*pSPARC->MD_dt/pSPARC->NPT_NP_qmass) < 0.0){ - if (rank == 0) - printf("The mass of thermostat variable NPT_NP_qmass is too small. Please try a larger thermostat mass."); - exit(EXIT_FAILURE); - } - pSPARC->Sv_NPT_NP = -2.0 * factor / (pSPARC->NPT_NP_qmass * (1.0 + sqrt(1.0 - factor * pSPARC->MD_dt / pSPARC->NPT_NP_qmass))); - #ifdef DEBUG - if (rank == 0) - printf("Sv_NPT_NP in the 2nd half step is %12.9f\n", pSPARC->Sv_NPT_NP); - #endif -} - -/* - @ brief: update positions of particles, value of thermostat variable and barostat variables in the step -*/ -void updatePosition(SPARC_OBJ *pSPARC) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - int judge = 0; - // update value of thermostat variable S_NPT_NP - double Stemp = pSPARC->S_NPT_NP; - double Snew; - int timeIter = 0; - while (judge == 0) { - timeIter++; - Snew = pSPARC->S_NPT_NP + pSPARC->MD_dt / 2.0 * (pSPARC->S_NPT_NP + Stemp) * pSPARC->Sv_NPT_NP; - if (fabs(Snew - Stemp) < 1e-7) { - judge = 1; - } - Stemp = Snew; - if (timeIter > pSPARC->maxTimeIter) { - judge = 1; - if (rank == 0) - printf("Reminder: The value of thermostat variable S_NPT_NP does not converge in %d iterations.\n", pSPARC->maxTimeIter); - } - } - #ifdef DEBUG - if (rank == 0) - printf("Stemp is %12.9f\n", Stemp); - #endif - // update values of barostat variables G_NPT_NP - double Gtmp[3], Gnew[3], Gpig[3], GpigOld[3]; - int i; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - Gtmp[i] = pSPARC->G_NPT_NP[i]; - GpigOld[i] = pow(pSPARC->G_NPT_NP[i], 2.0) * pSPARC->Pm_NPT_NP[i]; - } - } - judge = 0; timeIter = 0; - while (judge == 0){ - timeIter++; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - Gpig[i] = pow(Gtmp[i], 2.0) * pSPARC->Pm_NPT_NP[i]; - Gnew[i] = pSPARC->G_NPT_NP[i] + pSPARC->MD_dt / 2.0 * (pSPARC->S_NPT_NP/(pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0))*GpigOld[i] + Stemp/(pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0))*Gpig[i]); - } - } - judge = 1; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - if (fabs(Gnew[i] - Gtmp[i]) > 1e-7) { - judge = 0; - } - Gtmp[i] = Gnew[i]; - } - } - if (timeIter > pSPARC->maxTimeIter) { - judge = 1; - if (rank == 0) - printf("Reminder: The barostat variables G_NPT_NP do not converge in %d iterations.\n", pSPARC->maxTimeIter); - } - } - double G3[3]; - for (i = 0; i < 3; i++) { - if (pSPARC->NPTscaleVecs[i] == 1) { - pSPARC->G_NPT_NP[i] = Gtmp[i]; - G3[i] = pow(Gtmp[i], 2.0) * pSPARC->Pm_NPT_NP[i]; - } - } - #ifdef DEBUG - if (rank == 0) { - printf("pSPARC->G_NPT_NP[0] is %12.9f\n", pSPARC->G_NPT_NP[0]); - printf("pSPARC->G_NPT_NP[1] is %12.9f\n", pSPARC->G_NPT_NP[1]); - printf("pSPARC->G_NPT_NP[2] is %12.9f\n", pSPARC->G_NPT_NP[2]); - } - #endif - // update side lengths of cells and velocities of them - double scalex = sqrt(pSPARC->G_NPT_NP[0]) / pSPARC->range_x; - pSPARC->range_x = sqrt(pSPARC->G_NPT_NP[0]); - double scaley = sqrt(pSPARC->G_NPT_NP[1]) / pSPARC->range_y; - pSPARC->range_y = sqrt(pSPARC->G_NPT_NP[1]); - double scalez = sqrt(pSPARC->G_NPT_NP[2]) / pSPARC->range_z; - pSPARC->range_z = sqrt(pSPARC->G_NPT_NP[2]); - pSPARC->volumeCell = pSPARC->Jacbdet*pSPARC->range_x*pSPARC->range_y*pSPARC->range_z; - if (pSPARC->NPTscaleVecs[0] == 1) - pSPARC->range_x_velo = G3[0] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_x; - else - pSPARC->range_x_velo = 0.0; - if (pSPARC->NPTscaleVecs[1] == 1) - pSPARC->range_y_velo = G3[1] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_y; - else - pSPARC->range_y_velo = 0.0; - if (pSPARC->NPTscaleVecs[2] == 1) - pSPARC->range_z_velo = G3[2] * Stemp / (2.0*pSPARC->NPT_NP_bmass*pow(pSPARC->volumeCell, 2.0)) / pSPARC->range_z; - else - pSPARC->range_z_velo = 0.0; - // update positions of particles, and restore the values of particle velocities - int count = 0; - int atm; - for(atm = 0; atm < pSPARC->n_atom; atm++){ - pSPARC->atom_pos[count * 3] = (pSPARC->atom_pos[count * 3]) * scalex + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3]/Stemp); // - pSPARC->atom_pos[count * 3 + 1] = (pSPARC->atom_pos[count * 3 + 1]) * scaley + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 1]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 1]/Stemp); // - pSPARC->atom_pos[count * 3 + 2] = (pSPARC->atom_pos[count * 3 + 2]) * scalez + pSPARC->MD_dt/2.0 * (pSPARC->ion_vel[count * 3 + 2]/pSPARC->S_NPT_NP + pSPARC->ion_vel[count * 3 + 2]/Stemp); // - pSPARC->ion_vel[count * 3] /= Stemp; - pSPARC->ion_vel[count * 3 + 1] /= Stemp; - pSPARC->ion_vel[count * 3 + 2] /= Stemp; - count ++; - } - pSPARC->S_NPT_NP = Stemp; -} - -/** - * @ brief: function to convert non cartesian to cartesian coordinates, from initialization.c - */ -void nonCart2Cart(double *LatUVec, double *carCoord, double *nonCarCoord) { - carCoord[0] = LatUVec[0] * nonCarCoord[0] + LatUVec[3] * nonCarCoord[1] + LatUVec[6] * nonCarCoord[2]; - carCoord[1] = LatUVec[1] * nonCarCoord[0] + LatUVec[4] * nonCarCoord[1] + LatUVec[7] * nonCarCoord[2]; - carCoord[2] = LatUVec[2] * nonCarCoord[0] + LatUVec[5] * nonCarCoord[1] + LatUVec[8] * nonCarCoord[2]; -} - -/** - * @brief: function to convert cartesian to non cartesian coordinates, from initialization.c - */ -void Cart2nonCart(double *gradT, double *carCoord, double *nonCarCoord) { - nonCarCoord[0] = gradT[0] * carCoord[0] + gradT[1] * carCoord[1] + gradT[2] * carCoord[2]; - nonCarCoord[1] = gradT[3] * carCoord[0] + gradT[4] * carCoord[1] + gradT[5] * carCoord[2]; - nonCarCoord[2] = gradT[6] * carCoord[0] + gradT[7] * carCoord[1] + gradT[8] * carCoord[2]; -} - -/* -* @ brief: function to check if the atoms are too close to the boundary in case of bounded domain or to each other in general -*/ -void Check_atomlocation(SPARC_OBJ *pSPARC) { - int rank, ityp, i, atm, atm2, count, dir = 0, maxdir = 3, BC; - double length, temp, rc1 = 0.0, rc2 = 0.0, *rc, tol = 0.5;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - rc = (double *)malloc(pSPARC->Ntypes * sizeof(double) ); - for (ityp = 0; ityp < pSPARC->Ntypes; ityp++) { - rc[ityp] = 0.0; - for(i = 0; i <= pSPARC->psd[ityp].lmax; i++) - rc[ityp] = max(rc[ityp], pSPARC->psd[ityp].rc[i]); - } - // Check whether the two atoms are closer than rc - for(atm = 0; atm < pSPARC->n_atom - 1; atm++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm < count){ - rc1 = rc[ityp]; - break; - }else - continue; - } - for(atm2 = atm + 1; atm2 < pSPARC->n_atom; atm2++){ - count = 0; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - count += pSPARC->nAtomv[ityp]; - if(atm2 < count){ - rc2 = rc[ityp]; - break; - }else - continue; - } - temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * atm] - pSPARC->atom_pos[3 * atm2],2.0) + pow(pSPARC->atom_pos[3 * atm + 1] - pSPARC->atom_pos[3 * atm2 + 1],2.0) + pow(pSPARC->atom_pos[3 * atm + 2] - pSPARC->atom_pos[3 * atm2 + 2],2.0) )); - if(temp < (1 - tol) * (rc1 + rc2)){ - if(!rank) - printf("WARNING: Atoms too close to each other with interatomic distance of %E Bohr\n",temp); - atm2 = pSPARC->n_atom; - atm = pSPARC->n_atom - 1; - } - } - } - free(rc); - - wraparound_dynamics(pSPARC, pSPARC->atom_pos, 1); -} - -/* -* @ brief: function to wraparound atom positions for PBC -*/ -void wraparound_dynamics(SPARC_OBJ *pSPARC, double *coord, int opt) { - - int rank, atm, dir = 0, maxdir = 3, BC; - double length, coord_temp;// Change tol according to the situation - MPI_Comm_rank(MPI_COMM_WORLD,&rank); - - // Convert Cart to nonCart coordinates for non orthogonal cell - if(pSPARC->cell_typ != 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++) - Cart2nonCart_coord(pSPARC, coord+3*atm, coord+3*atm+1, coord+3*atm+2); - } - - while(dir < maxdir){ - if(dir == 0){ - length = pSPARC->range_x; - BC = pSPARC->BCx; - } - else if(dir == 1){ - length = pSPARC->range_y; - BC = pSPARC->BCy; - } - else if(dir == 2){ - length = pSPARC->range_z; - BC = pSPARC->BCz; - } - if(BC == 1){ - if (!((pSPARC->CyclixFlag) && (dir == 0))) { // if it is in cyclix coordinate and in x (radial) direction, we will not check it - for(atm = 0; atm < pSPARC->n_atom; atm++){ - if(coord[atm * 3 + dir] >= length || coord[atm * 3 + dir] < 0){ - if(!rank) - printf("ERROR: Atom number %d has crossed the boundary in %d direction",atm, dir); - exit(EXIT_FAILURE); - } - } - } - } else if(BC == 0){ - for(atm = 0; atm < pSPARC->n_atom; atm++){ - coord_temp = *(coord+3*atm+dir); - if (coord_temp < 0.0 || coord_temp >= length) - { - coord_temp = fmod(coord_temp,length); - double new_coord = coord_temp + (coord_temp<0.0)*length; - double shift = new_coord - *(coord+3*atm+dir); - *(coord+3*atm+dir) = new_coord; - if (pSPARC->CyclixFlag && opt == 1){ - wraparound_velocity(pSPARC, shift, dir, 3*atm); - } - } - } - } - dir ++; - } -} - -/* -* @ brief: function to wraparound velocities in MD and displacement vectors in relaxation for PBC -*/ -void wraparound_velocity(SPARC_OBJ *pSPARC, double shift, int dir, int loc) { - - if (dir == 1){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->ion_vel[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(shift) * vx -sin(shift) * vy; - pSPARC->d[loc+1] = sin(shift) * vx + cos(shift) * vy; - } - } else if (dir == 2){ - if (pSPARC->MDFlag == 1){ - double vx = pSPARC->ion_vel[loc]; double vy = pSPARC->ion_vel[loc+1]; - pSPARC->ion_vel[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->ion_vel[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - else if (pSPARC->RelaxFlag == 1){ - double vx = pSPARC->d[loc]; double vy = pSPARC->d[loc+1]; - pSPARC->d[loc] = cos(pSPARC->twist*shift) * vx -sin(pSPARC->twist*shift) * vy; - pSPARC->d[loc+1] = sin(pSPARC->twist*shift) * vx + cos(pSPARC->twist*shift) * vy; - } - } - -} - -/* - @ brief: function to write all relevant DFT quantities generated during MD simulation -*/ -void Print_fullMD(SPARC_OBJ *pSPARC, FILE *output_md, double *avgvel, double *maxvel, double *mindis) { - int atm; - - // Print Description of all variables - if(pSPARC->MDCount == -1){ - fprintf(output_md,":Description: \n\n"); - fprintf(output_md,":Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr \n"); - fprintf(output_md,":Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu \n" - " where atu is the atomic unit of time, hbar/Ha \n"); - fprintf(output_md,":Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr \n"); - fprintf(output_md,":Desc_MDTM: MD time. Unit=second \n"); - fprintf(output_md,":Desc_TEL: Electronic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TIO: Ionic temperature. Unit=Kelvin \n"); - fprintf(output_md,":Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KEN: Ionic kinetic energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom \n" - " where N = number of particles, k = Boltzmann constant\n"); - fprintf(output_md,":Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_UEN: Internal energy. Unit=Ha/atom \n"); - fprintf(output_md,":Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom \n"); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":Desc_TENX: Total energy of extended system. Unit=Ha/atom \n"); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":Desc_CELL: lengths of three lattice vectors. Unit = Bohr \n"); - else - fprintf(output_md,":Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 \n"); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":Desc_NPT_NH_HAMIL: Hamiltonian of the NPT_NH system, formula (5.4) in (M. E. Tuckerman et al, 2006). Unit = Ha/atom \n"); - else - fprintf(output_md,":Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom \n"); - } - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - fprintf(output_md,":Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) \n"); - } - if((pSPARC->Calc_pres == 1 || pSPARC->Calc_stress == 1) && pSPARC->BC == 2){ - fprintf(output_md,":Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa \n"); - fprintf(output_md,":Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa \n"); - fprintf(output_md,":Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa \n" - " where N = number of particles, k = Boltzmann constant, V = volume\n"); - } - - #ifdef DEBUG - fprintf(output_md,":Desc_ST: (DEBUG mode only) Tags ending in 'ST' describe statistics. Printed are the mean and standard deviation, respectively. \n"); - #endif - - fprintf(output_md,":Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu \n"); - fprintf(output_md,":Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr \n"); - fprintf(output_md, "\n\n"); - } else{ - double ken_ig = 0.0; - ken_ig = 3.0/2.0 * pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T; - - // Print Temperature and energy - fprintf(output_md,":TWIST: %.15g\n", pSPARC->twist); - fprintf(output_md,":TEL: %.15g\n", pSPARC->elec_T); - fprintf(output_md,":TIO: %.15g\n", pSPARC->ion_T); - fprintf(output_md,":TEN: %18.10E\n", pSPARC->TE); - fprintf(output_md,":KEN: %18.10E\n", pSPARC->KE); - fprintf(output_md,":KENIG:%18.10E\n",ken_ig/pSPARC->n_atom); - fprintf(output_md,":FEN: %18.10E\n", pSPARC->PE); - fprintf(output_md,":UEN: %18.10E\n", pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom); - fprintf(output_md,":TSEN:%18.10E\n", pSPARC->Entropy/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENX:%18.10E \n", pSPARC->TE_ext); - } - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) - fprintf(output_md,":NPT_NH_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NH/pSPARC->n_atom); - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) - fprintf(output_md,":NPT_NP_HAMIL:%18.10E \n", pSPARC->Hamiltonian_NPT_NP/pSPARC->n_atom); - - // Print atomic position - if(pSPARC->PrintAtomPosFlag){ - fprintf(output_md,":R:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - } - - // Print velocity - if(pSPARC->PrintAtomVelFlag){ - fprintf(output_md,":V:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - } - - // Print Forces - if(pSPARC->PrintForceFlag){ - fprintf(output_md,":F:\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(output_md,"%18.10E %18.10E %18.10E\n", pSPARC->forces[3 * atm], pSPARC->forces[3 * atm + 1], pSPARC->forces[3 * atm + 2]); - } - } - - // Print length of lattice vectors - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0 || strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - if (pSPARC->Flag_latvec_scale == 0) - fprintf(output_md,":CELL: %18.10E %18.10E %18.10E\n", pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); - else - fprintf(output_md,":LATVEC_SCALE: %18.10E %18.10E %18.10E\n", pSPARC->range_x/pSPARC->initialLatVecLength[0], pSPARC->range_y/pSPARC->initialLatVecLength[1], pSPARC->range_z/pSPARC->initialLatVecLength[2]); - } - - // Print stress - if(pSPARC->Calc_stress == 1){ - fprintf(output_md,":STRIO:\n"); - PrintStress (pSPARC, pSPARC->stress_i, output_md); - fprintf(output_md,":STRESS:\n"); - double stress_e[6]; // electronic stress - for (int i = 0; i < 6; i++) - stress_e[i] = pSPARC->stress[i] - pSPARC->stress_i[i]; - PrintStress (pSPARC, stress_e, output_md); - } - - // print pressure - if ((pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) && pSPARC->BC == 2) { - // find pressure of ideal gas: NkT/V - // Define measure of unit cell - double cell_measure = pSPARC->Jacbdet; - if(pSPARC->BCx == 0) - cell_measure *= pSPARC->range_x; - if(pSPARC->BCy == 0) - cell_measure *= pSPARC->range_y; - if(pSPARC->BCz == 0) - cell_measure *= pSPARC->range_z; - double pres_ig = 0.0; - pres_ig = pSPARC->n_atom * pSPARC->kB * pSPARC->ion_T / cell_measure; - - fprintf(output_md,":PRESIO: %18.10E\n", pSPARC->pres_i*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRES: %18.10E\n", (pSPARC->pres-pSPARC->pres_i)*CONST_HA_BOHR3_GPA); - fprintf(output_md,":PRESIG: %18.10E\n", pres_ig*CONST_HA_BOHR3_GPA); // Ideal Gas - - } - - #ifdef DEBUG - // Print Statistical properties - fprintf(output_md,":TELST: %18.10E %18.10E\n", pSPARC->mean_elec_T, pSPARC->std_elec_T); - fprintf(output_md,":TIOST: %18.10E %18.10E\n", pSPARC->mean_ion_T, pSPARC->std_ion_T); - fprintf(output_md,":TENST: %18.10E %18.10E\n", pSPARC->mean_TE, pSPARC->std_TE); - fprintf(output_md,":KENST: %18.10E %18.10E\n", pSPARC->mean_KE, pSPARC->std_KE); - fprintf(output_md,":FENST: %18.10E %18.10E\n", pSPARC->mean_PE, pSPARC->std_PE); - fprintf(output_md,":UENST: %18.10E %18.10E\n", pSPARC->mean_U, pSPARC->std_U); - fprintf(output_md,":TSENST: %18.10E %18.10E\n", pSPARC->mean_Entropy, pSPARC->std_Entropy); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(output_md,":TENXST: %18.10E %18.10E\n", pSPARC->mean_TE_ext, pSPARC->std_TE_ext); - } - fprintf(output_md,":AVGV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",avgvel[atm]); - fprintf(output_md,":MAXV:\n"); - for(atm = 0; atm < pSPARC->Ntypes; atm++) - fprintf(output_md," %18.10E\n",maxvel[atm]); - #endif - fprintf(output_md,":MIND:\n"); - char elemType1[8], elemType2[8]; - int typeIndex, typeIndex2, pairIndex; - for (typeIndex = 0; typeIndex < pSPARC->Ntypes; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType1, mindis[typeIndex]); - } - pairIndex = 0; - for(typeIndex = 0; typeIndex < pSPARC->Ntypes - 1; typeIndex++) { - find_element(elemType1, &pSPARC->atomType[L_ATMTYPE*typeIndex]); - for (typeIndex2 = typeIndex + 1; typeIndex2 < pSPARC->Ntypes; typeIndex2++) { - find_element(elemType2, &pSPARC->atomType[L_ATMTYPE*typeIndex2]); - fprintf(output_md,"%s - %s: %18.10E\n", elemType1, elemType2, mindis[pairIndex + pSPARC->Ntypes]); - pairIndex++; - } - } - } -} - -/* - @ brief function to evaluate the qunatities of interest in a MD simulation -*/ -void MD_QOI(SPARC_OBJ *pSPARC, double *avgvel, double *maxvel, double *mindis) { - // Compute MD energies (TE=KE+PE)/atom and temperature - pSPARC->ion_T = 2 * pSPARC->KE /(pSPARC->kB * pSPARC->dof); - if(pSPARC->ion_elec_eqT == 1){ - pSPARC->elec_T = pSPARC->ion_T; - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - } - pSPARC->PE = pSPARC->Etot / pSPARC->n_atom; - pSPARC->KE = pSPARC->KE/pSPARC->n_atom; - pSPARC->TE = (pSPARC->PE + pSPARC->KE); - // Extended System (Ionic system + Thermostat) energy - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - pSPARC->TE_ext = (0.5 * pSPARC->qmass * pow(pSPARC->xi_nose, 2.0) + pSPARC->dof * pSPARC->kB * pSPARC->thermos_T * pSPARC->snose)/pSPARC->n_atom + pSPARC->TE; - } - // Compute Ionic stress/pressure - if(pSPARC->Calc_stress == 1 || pSPARC->Calc_pres == 1) - Calculate_ionic_stress(pSPARC); - - // Calculate_stress(pSPARC); -#ifdef DEBUG - // MD Statistics - double mean_TE_old, mean_KE_old, mean_PE_old, mean_U_old, mean_Eent_old, mean_Ti_old, mean_Te_old; - int Count = pSPARC->MDCount + (pSPARC->RestartFlag == 0) ; - mean_Te_old = pSPARC->mean_elec_T; - mean_Ti_old = pSPARC->mean_ion_T; - mean_TE_old = pSPARC->mean_TE; - mean_KE_old = pSPARC->mean_KE; - mean_PE_old = pSPARC->mean_PE; - mean_U_old = pSPARC->mean_U; - mean_Eent_old = pSPARC->mean_Entropy; - pSPARC->mean_elec_T = (mean_Te_old * (Count - 1) + pSPARC->elec_T)/ Count; - pSPARC->mean_ion_T = (mean_Ti_old * (Count - 1) + pSPARC->ion_T)/ Count; - pSPARC->mean_TE = (mean_TE_old * (Count - 1) + pSPARC->TE)/ Count; - pSPARC->mean_KE = (mean_KE_old * (Count - 1) + pSPARC->KE)/ Count; - pSPARC->mean_PE = (mean_PE_old * (Count - 1) + pSPARC->PE)/ Count; - pSPARC->mean_U = (mean_U_old * (Count - 1) + pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->mean_Entropy = (mean_Eent_old * (Count - 1) + pSPARC->Entropy/pSPARC->n_atom)/ Count; - pSPARC->std_elec_T = sqrt(fabs( ((pow(pSPARC->std_elec_T,2.0) + pow(mean_Te_old,2.0)) * (Count - 1) + pow(pSPARC->elec_T,2.0))/Count - pow(pSPARC->mean_elec_T,2.0) )); - pSPARC->std_ion_T = sqrt(fabs( ((pow(pSPARC->std_ion_T,2.0) + pow(mean_Ti_old,2.0)) * (Count - 1) + pow(pSPARC->ion_T,2.0))/Count - pow(pSPARC->mean_ion_T,2.0) )); - pSPARC->std_TE = sqrt(fabs( ((pow(pSPARC->std_TE,2.0) + pow(mean_TE_old,2.0)) * (Count - 1) + pow(pSPARC->TE,2.0))/Count - pow(pSPARC->mean_TE,2.0) )); - pSPARC->std_KE = sqrt(fabs( ((pow(pSPARC->std_KE,2.0) + pow(mean_KE_old,2.0)) * (Count - 1) + pow(pSPARC->KE,2.0))/Count - pow(pSPARC->mean_KE,2.0) )); - pSPARC->std_PE = sqrt(fabs( ((pow(pSPARC->std_PE,2.0) + pow(mean_PE_old,2.0)) * (Count - 1) + pow(pSPARC->PE,2.0))/Count - pow(pSPARC->mean_PE,2.0) )); - pSPARC->std_U = sqrt(fabs( ((pow(pSPARC->std_U,2.0) + pow(mean_U_old,2.0)) * (Count - 1) + pow(pSPARC->PE - pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_U,2.0) )); - pSPARC->std_Entropy = sqrt(fabs( ((pow(pSPARC->std_Entropy,2.0) + pow(mean_Eent_old,2.0)) * (Count - 1) + pow(pSPARC->Entropy/pSPARC->n_atom,2.0))/Count - pow(pSPARC->mean_Entropy,2.0) )); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - double mean_TEx_old = pSPARC->mean_TE_ext; - pSPARC->mean_TE_ext = (mean_TEx_old * (Count - 1) + pSPARC->TE_ext)/ Count; - pSPARC->std_TE_ext = sqrt(fabs( ((pow(pSPARC->std_TE_ext,2.0) + pow(mean_TEx_old,2.0)) * (Count - 1) + pow(pSPARC->TE_ext,2.0))/Count - pow(pSPARC->mean_TE_ext,2.0) )); - } -#endif - - // Average and maximum speed - int ityp, atm, cc = 0; - double temp; - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - maxvel[ityp] = 0.0; - avgvel[ityp] = 0.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - temp = fabs(sqrt(pow(pSPARC->ion_vel[3 * cc],2.0) + pow(pSPARC->ion_vel[3 * cc + 1],2.0) + pow(pSPARC->ion_vel[3 * cc + 2],2.0))); - if(temp > maxvel[ityp]) - maxvel[ityp] = temp; - avgvel[ityp] += temp; - cc += 1; - } - avgvel[ityp] /= pSPARC->nAtomv[ityp]; - } - - // Average and minimum distance - //*avgdis = pow((pSPARC->range_x * pSPARC->range_y * pSPARC->range_z)/pSPARC->n_atom,1/3.0); - int atm2, ityp2, cc2, pairIndex; - cc = 0; - - // Store the cell as a 3x3 lattice vector - double *lattice = (double *)calloc(sizeof(double), 9); - double cell[3] = {pSPARC->range_x, pSPARC->range_y, pSPARC->range_z}; - double dr[3]; - int row, col; - for (row = 0; row < 3; row++) { - lattice[row*3] = pSPARC->LatUVec[row*3] * cell[row]; - lattice[row*3 + 1] = pSPARC->LatUVec[row*3 + 1] * cell[row]; - lattice[row*3 + 2] = pSPARC->LatUVec[row*3 + 2] * cell[row]; - } - - // Calculate the inverse of lattice-vector - double LV_inv[9], U[9], S[3], VT[9], superb[2], temp_mat[9], LatVec[9]; - double S_inv[9] = {0}; - int m = 3; - - for (int JJ = 0; JJ < 9; JJ++) { - LatVec[JJ] = lattice[JJ]; - } - - /* Calculating pinv(LatVec): This is necessary because for extremely skewed LV, the LV maybe close to singular */ - // Compute SVD of LatVec(LV) first: LV = U * S * V^T - LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A', m, m, LatVec, m, S, U, m, VT, m, superb); - - // First compute S^{-1} - for (int i = 0; i < 3; i++) { - if (S[i] > 1e-12) S_inv[i * 3 + i] = 1.0/S[i]; - } - - // Compute LV^{-1} = V * S^{-1} * U^T - cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, m, m, 1.0, VT, m, S_inv, m, 0.0, temp_mat, m); - cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, m, m, 1.0, temp_mat, m, U, m, 0.0, LV_inv, m); - - for(ityp = 0; ityp < pSPARC->Ntypes; ityp++){ - mindis[ityp] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp] - 1; atm++){ - for(atm2 = atm + 1; atm2 < pSPARC->nAtomv[ityp]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[ityp]) - mindis[ityp] = temp; - } - } - cc += pSPARC->nAtomv[ityp]; - } - cc = 0; - pairIndex = pSPARC->Ntypes; - for(ityp = 0; ityp < pSPARC->Ntypes - 1; ityp++){ - cc2 = pSPARC->nAtomv[ityp] + cc; - for(ityp2 = ityp + 1; ityp2 < pSPARC->Ntypes; ityp2++){ - // mindis[pSPARC->Ntypes - 1 + ityp*(pSPARC->Ntypes-1 + pSPARC->Ntypes-1-(ityp - 1))/2 + ityp2 - ityp] = 1000000000.0; - mindis[pairIndex] = 1000000000.0; - for(atm = 0; atm < pSPARC->nAtomv[ityp]; atm++){ - for(atm2 = 0; atm2 < pSPARC->nAtomv[ityp2]; atm2++){ - // temp = fabs(sqrt(pow(pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1],2.0) + pow(pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2],2.0) )); - - // Vector connecting atoms atm and atm2 - dr[0] = pSPARC->atom_pos[3 * (atm + cc)] - pSPARC->atom_pos[3 * (atm2 + cc2)]; - dr[1] = pSPARC->atom_pos[3 * (atm + cc) + 1] - pSPARC->atom_pos[3 * (atm2 + cc2) + 1]; - dr[2] = pSPARC->atom_pos[3 * (atm + cc) + 2] - pSPARC->atom_pos[3 * (atm2 + cc2) + 2]; - - double frac[3], dr_pbc[3]; - - // Minimum Image Convention (MIC) in fractional coordinates - // frac = LV^{-1} * dr - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, LV_inv, m, dr, 1, 0.0, frac, 1); - - // Wrap into [-0.5, 0.5) - frac[0] -= round(frac[0]); - frac[1] -= round(frac[1]); - frac[2] -= round(frac[2]); - - // dr_pbc = lattice * frac - cblas_dgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0, lattice, 3, frac, 1, 0.0, dr_pbc, 1); - - // Calculate distance - temp = sqrt(dr_pbc[0]*dr_pbc[0] + dr_pbc[1]*dr_pbc[1] + dr_pbc[2]*dr_pbc[2]); - - if(temp < mindis[pairIndex]) - mindis[pairIndex] = temp; - } - } - pairIndex++; - cc2 += pSPARC->nAtomv[ityp2]; - } - cc += pSPARC->nAtomv[ityp]; - } - free(lattice); -} - -/* - @ brief: function to write all relevant quantities needed for MD restart -*/ -void PrintMD(SPARC_OBJ *pSPARC, int Flag, int print_restart_typ) { - FILE *mdout; - if(!Flag){ - mdout = fopen(pSPARC->restartC_Filename,"r+"); - if(mdout == NULL){ - printf("\nCannot open file \"%s\"\n",pSPARC->restartC_Filename); - exit(EXIT_FAILURE); - } - // Update MD Count - fprintf(mdout,":STOPCOUNT: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - fclose(mdout); - - } - else{ - if (print_restart_typ == 0) { - // Transfer the restart content to a file before overwriting - Rename_restart(pSPARC); - // Overwrite in the restart file - mdout = fopen(pSPARC->restartC_Filename,"w"); - } - else - mdout = fopen(pSPARC->restart_Filename,"w"); - - // Print restart Count - fprintf(mdout,":MDSTEP: %d\n", pSPARC->MDCount + pSPARC->restartCount + (pSPARC->RestartFlag == 0)); - // Print atomic position - int atm; - fprintf(mdout,":R(Bohr):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->atom_pos[3 * atm], pSPARC->atom_pos[3 * atm + 1], pSPARC->atom_pos[3 * atm + 2]); - } - - // Print velocity - fprintf(mdout,":V(Bohr/atu):\n"); - for(atm = 0; atm < pSPARC->n_atom; atm++){ - fprintf(mdout,"%18.10E %18.10E %18.10E\n", pSPARC->ion_vel[3 * atm], pSPARC->ion_vel[3 * atm + 1], pSPARC->ion_vel[3 * atm + 2]); - } - // Print extended system parameters in case of NVT - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - fprintf(mdout,":snose: %.15g\n", pSPARC->snose); - fprintf(mdout,":xinose: %.15g\n", pSPARC->xi_nose); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_T); - } - // Print extended system parameters in case of NPT-NH - if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - int thenos; - fprintf(mdout,":NPT_NH_QMASS: %d", pSPARC->NPT_NHnnos); - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g",pSPARC->NPT_NHqmass[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_BMASS: %.15g\n",pSPARC->NPT_NHbmass); - fprintf(mdout,":NPT_NH_vlogs: %d", pSPARC->NPT_NHnnos); // velocities of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->vlogs[thenos]); - } - fprintf(mdout,"\n"); - fprintf(mdout,":NPT_NH_vlogv: %.15g\n", pSPARC->vlogv); // velocities of the virtual baro parameter - fprintf(mdout,":NPT_NH_xlogs: %d", pSPARC->NPT_NHnnos); // positions of virtual thermal parameters - for (thenos = 0; thenos < pSPARC->NPT_NHnnos; thenos++) { - if (thenos%5 == 0){ - fprintf(mdout,"\n"); - } - fprintf(mdout," %.15g", pSPARC->xlogs[thenos]); - } - fprintf(mdout,"\n"); - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - } - // Print extended system parameters in case of NPT-NP - if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - fprintf(mdout,":NPT_NP_QMASS: %.15g\n", pSPARC->NPT_NP_qmass); - fprintf(mdout,":NPT_NP_BMASS: %.15g\n", pSPARC->NPT_NP_bmass); - fprintf(mdout,":NPT_NP_Sv: %.15g\n", pSPARC->Sv_NPT_NP); // velocity of virtual thermal parameter - fprintf(mdout,":NPT_NP_Pm: %.15g %.15g %.15g\n", pSPARC->Pm_NPT_NP[0], pSPARC->Pm_NPT_NP[1], pSPARC->Pm_NPT_NP[2]); // velocity of virtual baro parameter - fprintf(mdout,":NPT_NP_S: %.15g\n", pSPARC->S_NPT_NP); // value of virtual thermal parameter - fprintf(mdout,":NPT_NP_range_x_velo: %.15g\n", pSPARC->range_x_velo); // velocity of virtual x baro parameter - fprintf(mdout,":NPT_NP_range_y_velo: %.15g\n", pSPARC->range_y_velo); // velocity of virtual y baro parameter - fprintf(mdout,":NPT_NP_range_z_velo: %.15g\n", pSPARC->range_z_velo); // velocity of virtual z baro parameter - if (pSPARC->Flag_latvec_scale == 0) - fprintf(mdout,":CELL: %.15g %.15g %.15g\n",pSPARC->range_x,pSPARC->range_y,pSPARC->range_z); //(no variable for position of barostat variable) - else - fprintf(mdout,":LATVEC_SCALE: %.15g %.15g %.15g\n",pSPARC->range_x/pSPARC->initialLatVecLength[0],pSPARC->range_y/pSPARC->initialLatVecLength[1],pSPARC->range_z/pSPARC->initialLatVecLength[2]); - fprintf(mdout,":TTHRMI(K): %.15g\n", pSPARC->thermos_Ti); - fprintf(mdout,":TARGET_PRESSURE: %.15g GPa\n",pSPARC->prtarget * 29421.02648438959); - fprintf(mdout,":NPT_NP_ini_Hamiltonian: %.15g\n", pSPARC->init_Hamil_NPT_NP); - } - // Print temperature - fprintf(mdout,":TEL(K): %.15g\n", pSPARC->elec_T); - fprintf(mdout,":TIO(K): %.15g\n", pSPARC->ion_T); - - fclose(mdout); - } -} - -/* -@ brief function to read the restart file for MD restart -*/ -void RestartMD(SPARC_OBJ *pSPARC) { - int rank, position, l_buff = 0; -#ifdef DEBUG - double t1, t2; -#endif - char *buff; - FILE *rst_fp = NULL; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Open the restart file - if(!rank){ - //char rst_Filename[L_STRING]; - if( access(pSPARC->restart_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restart_Filename,"r"); - else if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rst_fp = fopen(pSPARC->restartC_Filename,"r"); - else - rst_fp = fopen(pSPARC->restartP_Filename,"r"); - } -#ifdef DEBUG - if(!rank) - printf("Reading .restart file for MD\n"); -#endif - // Allocate memory for dynamic variables - pSPARC->ion_vel = (double *)malloc( 3 * pSPARC->n_atom * sizeof(double) ); - if (pSPARC->ion_vel == NULL) { - printf("\nCannot allocate memory for ion velocity array!\n"); - exit(EXIT_FAILURE); - } - - // Allocate memory for Pack and Unpack to be used later for broadcasting - if(pSPARC->RestartFlag == 1){ - // l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - l_buff = (2 + 1) * sizeof(int) + (6 * pSPARC->n_atom + (5 + 3*pSPARC->NPT_NHnnos + 9)) * sizeof(double); - } - else if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + (5 + 14)) * sizeof(double); - } - else { - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 5) * sizeof(double); - } - } - else if(pSPARC->RestartFlag == -1) - l_buff = 2 * sizeof(int) + (6 * pSPARC->n_atom + 3) * sizeof(double); - - buff = (char *)malloc( l_buff*sizeof(char) ); - if (buff == NULL) { - printf("\nmemory cannot be allocated for buffer\n"); - exit(EXIT_FAILURE); - } - if(!rank){ - char str[L_STRING]; - int atm; - while (fscanf(rst_fp,"%s",str) != EOF){ - if (strcmpi(str, ":STOPCOUNT:") == 0) - fscanf(rst_fp,"%d",&pSPARC->StopCount); - else if (strcmpi(str,":MDSTEP:") == 0) - fscanf(rst_fp,"%d",&pSPARC->restartCount); - else if (strcmpi(str,":R(Bohr):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->atom_pos[3 * atm], &pSPARC->atom_pos[3 * atm + 1], &pSPARC->atom_pos[3 * atm + 2]); - else if (strcmpi(str,":V(Bohr/atu):") == 0) - for(atm = 0; atm < pSPARC->n_atom; atm++) - fscanf(rst_fp,"%lf %lf %lf", &pSPARC->ion_vel[3 * atm], &pSPARC->ion_vel[3 * atm + 1], &pSPARC->ion_vel[3 * atm + 2]); - else if (strcmpi(str,":snose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->snose); - else if (strcmpi(str,":xinose:") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->xi_nose); - else if (strcmpi(str,":TEL(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->elec_T); - else if (strcmpi(str,":TIO(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->ion_T); - else if (strcmpi(str,":TTHRMI(K):") == 0 && pSPARC->RestartFlag == 1) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - if (strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) { - if (strcmpi(str,":NPT_NH_QMASS:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->NPT_NHqmass[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_vlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->vlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - else if (strcmpi(str,":NPT_NH_xlogs:") == 0) { - fscanf(rst_fp,"%d",&pSPARC->NPT_NHnnos); - for (int subscript_NPTNH_qmass = 0; subscript_NPTNH_qmass < pSPARC->NPT_NHnnos; subscript_NPTNH_qmass++){ - fscanf(rst_fp,"%lf",&pSPARC->xlogs[subscript_NPTNH_qmass]); - } - fscanf(rst_fp, "%*[^\n]\n"); - } - - else if (strcmpi(str,":NPT_NH_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NHbmass); - else if (strcmpi(str,":NPT_NH_vlogv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->vlogv); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - - if (pSPARC->NPTscaleVecs[0] == 1) pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NH only support expanding with a constant ratio - else if (pSPARC->NPTscaleVecs[1] == 1) pSPARC->scale = nowRange_y / pSPARC->range_y; - else pSPARC->scale = nowRange_z / pSPARC->range_z; - - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - } - if (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0) { - if (strcmpi(str,":NPT_NP_QMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_qmass); - else if (strcmpi(str,":NPT_NP_Sv:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->Sv_NPT_NP); - else if (strcmpi(str,":NPT_NP_S:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->S_NPT_NP); - else if (strcmpi(str,":NPT_NP_BMASS:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->NPT_NP_bmass); - else if (strcmpi(str,":NPT_NP_range_x_velo:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->range_x_velo); - else if (strcmpi(str,":NPT_NP_range_y_velo:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->range_y_velo); - else if (strcmpi(str,":NPT_NP_range_z_velo:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->range_z_velo); - else if (strcmpi(str,":CELL:") == 0) { - double nowRange_x, nowRange_y, nowRange_z; - fscanf(rst_fp,"%lf", &nowRange_x); fscanf(rst_fp,"%lf", &nowRange_y); fscanf(rst_fp,"%lf", &nowRange_z); - fscanf(rst_fp, "%*[^\n]\n"); - - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":LATVEC_SCALE:") == 0) { - double nowLatScale_x, nowLatScale_y, nowLatScale_z; - fscanf(rst_fp,"%lf", &nowLatScale_x); fscanf(rst_fp,"%lf", &nowLatScale_y); fscanf(rst_fp,"%lf", &nowLatScale_z); - fscanf(rst_fp, "%*[^\n]\n"); - - double nowRange_x, nowRange_y, nowRange_z; - pSPARC->initialLatVecLength[0] = sqrt(pSPARC->LatVec[0]*pSPARC->LatVec[0] + pSPARC->LatVec[1]*pSPARC->LatVec[1] + pSPARC->LatVec[2]*pSPARC->LatVec[2]); - pSPARC->initialLatVecLength[1] = sqrt(pSPARC->LatVec[3]*pSPARC->LatVec[3] + pSPARC->LatVec[4]*pSPARC->LatVec[4] + pSPARC->LatVec[5]*pSPARC->LatVec[5]); - pSPARC->initialLatVecLength[2] = sqrt(pSPARC->LatVec[6]*pSPARC->LatVec[6] + pSPARC->LatVec[7]*pSPARC->LatVec[7] + pSPARC->LatVec[8]*pSPARC->LatVec[8]); - nowRange_x = pSPARC->initialLatVecLength[0]*nowLatScale_x; - nowRange_y = pSPARC->initialLatVecLength[1]*nowLatScale_y; - nowRange_z = pSPARC->initialLatVecLength[2]*nowLatScale_z; - pSPARC->scale = nowRange_x / pSPARC->range_x; // now NPT_NP only support homogeneous expansion, - // compute scale from x is enough - pSPARC->range_x = nowRange_x; - pSPARC->range_y = nowRange_y; - pSPARC->range_z = nowRange_z; - } - else if (strcmpi(str,":TTHRMI(K):") == 0) - fscanf(rst_fp,"%lf", &pSPARC->thermos_Ti); - else if (strcmpi(str,":TARGET_PRESSURE:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->prtarget); - else if (strcmpi(str,":NPT_NP_ini_Hamiltonian:") == 0) - fscanf(rst_fp,"%lf", &pSPARC->init_Hamil_NPT_NP); - } - } - fclose(rst_fp); - - // Pack the variables - position = 0; - MPI_Pack(&pSPARC->StopCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->restartCount, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Pack(&pSPARC->elec_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->ion_T, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Pack(&pSPARC->snose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->xi_nose, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Pack(&pSPARC->NPT_NHnnos, 1, MPI_INT, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - - MPI_Pack(&pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->vlogv, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Pack(&pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->Sv_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->S_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z_velo, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->scale, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_x, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_y, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->range_z, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->thermos_Ti, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->prtarget, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - MPI_Pack(&pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, buff, l_buff, &position, MPI_COMM_WORLD); - } - } - - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); - } else{ -#ifdef DEBUG - t1 = MPI_Wtime(); -#endif - // broadcast the packed buffer - MPI_Bcast(buff, l_buff, MPI_PACKED, 0, MPI_COMM_WORLD); -#ifdef DEBUG - t2 = MPI_Wtime(); - if (rank == 0) printf(GRN "MPI_Bcast (.restart MD) packed buff of length %d took %.3f ms\n" RESET, l_buff,(t2-t1)*1000); -#endif - // unpack the variables - position = 0; - MPI_Unpack(buff, l_buff, &position, &pSPARC->StopCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->restartCount, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->atom_pos, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->ion_vel, 3*pSPARC->n_atom, MPI_DOUBLE, MPI_COMM_WORLD); - if(pSPARC->RestartFlag == 1){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->elec_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->ion_T, 1, MPI_DOUBLE, MPI_COMM_WORLD); - if(strcmpi(pSPARC->MDMeth,"NVT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->snose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->xi_nose, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NH") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHnnos, 1, MPI_INT, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->NPT_NHqmass, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->vlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, pSPARC->xlogs, pSPARC->NPT_NHnnos, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NHbmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->vlogv, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - else if(strcmpi(pSPARC->MDMeth,"NPT_NP") == 0){ - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_qmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->Sv_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->S_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - - MPI_Unpack(buff, l_buff, &position, &pSPARC->NPT_NP_bmass, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z_velo, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->scale, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_x, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_y, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->range_z, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->thermos_Ti, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->prtarget, 1, MPI_DOUBLE, MPI_COMM_WORLD); - MPI_Unpack(buff, l_buff, &position, &pSPARC->init_Hamil_NPT_NP, 1, MPI_DOUBLE, MPI_COMM_WORLD); - } - } - - } - if(pSPARC->RestartFlag == 1) { - pSPARC->Beta = 1.0/(pSPARC->elec_T * pSPARC->kB); - if((strcmpi(pSPARC->MDMeth,"NPT_NH") == 0) || (strcmpi(pSPARC->MDMeth,"NPT_NP") == 0)) { - reinitialize_mesh_NPT(pSPARC); - } - } - free(buff); -} - - - -/* -@ brief: function to rename the restart file -*/ -void Rename_restart(SPARC_OBJ *pSPARC) { - if( access(pSPARC->restartC_Filename, F_OK ) != -1 ) - rename(pSPARC->restartC_Filename, pSPARC->restartP_Filename); -} - From 95d9add400b097c5c8f9f8b85adeb323444579d8 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 18:28:18 -0400 Subject: [PATCH 80/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- tests/SPARC_testing_script.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/SPARC_testing_script.py b/tests/SPARC_testing_script.py index de849256..f281c398 100644 --- a/tests/SPARC_testing_script.py +++ b/tests/SPARC_testing_script.py @@ -225,7 +225,7 @@ SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## -SYSTEMS["systemname"].append('Al18C2_NPTNP_aeqb_c') +SYSTEMS["systemname"].append('Al18Si18_NPTNP_aeqb_c') SYSTEMS["directory"].append("./") SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) @@ -260,7 +260,7 @@ SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## -SYSTEMS["systemname"].append('Al18C2_NPH_aeqc_b') +SYSTEMS["systemname"].append('Al18Si18_NPH_aeqc_b') SYSTEMS["directory"].append("./") SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nph']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) From 5df06eea73fa7a90cb276c614d56c063c5a0aa2a Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 18:28:58 -0400 Subject: [PATCH 81/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/README.md b/tests/README.md index 6ed07262..5a0b305b 100644 --- a/tests/README.md +++ b/tests/README.md @@ -49,7 +49,7 @@ The systems in the testing suites are classified with a set of tags which descri * SCF Mixing and preconditioner: `potmix`,`denmix`,`kerker`. * Calculation type: `scf`,`relax_atom`,`relax_cell`,`relax_full`,`md`. * Relaxation type: `nlcg`,`lbfgs`,`fire`. - * MD type: `nvtnh`,`nvkg`,`nve`,`npt`. + * MD type: `nvtnh`,`nvkg`,`nve`,`nptnh`,`nptnp`,`nph`. * K-point sampling: `gamma`,`kpt`. * Spin polarization: `spin`,`SOC`. * Methods: `highT`,`SQ3`. From b3fa9b28fee584594a9a57017e8869ba89b4af72 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Sun, 5 Apr 2026 20:05:21 -0400 Subject: [PATCH 82/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- tests/SPARC_testing_script.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/SPARC_testing_script.py b/tests/SPARC_testing_script.py index f281c398..242effd9 100644 --- a/tests/SPARC_testing_script.py +++ b/tests/SPARC_testing_script.py @@ -13,11 +13,11 @@ # Other parameters to run the test (can be changed by the user) nprocs_tests = 12 # In default tests are run with 24 processors per node -nnodes_tests = 4 # In default tests are run with 1 node -npbs = 10 # By default (number of script files the tests are distributed to) +nnodes_tests = 3 # In default tests are run with 1 node +npbs = 40 # By default (number of script files the tests are distributed to) launch_cluster_extension = ".sbatch" # extension of the file used to launch the jobs on the cluster by default it is .sbatch command_launch_extension = "sbatch" # Command to launch the script to ask for resources on the cluster (example: qsub launch.pbs) -MPI_command = "mpirun -np 48" # MPI command to run the executable on the given cluster +MPI_command = "mpirun -np 36" # MPI command to run the executable on the given cluster @@ -227,7 +227,7 @@ ################################################################################################################## SYSTEMS["systemname"].append('Al18Si18_NPTNP_aeqb_c') SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nptnp']) +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## SYSTEMS["systemname"].append('Al18C2_NPTNP_onlyc') @@ -262,7 +262,7 @@ ################################################################################################################## SYSTEMS["systemname"].append('Al18Si18_NPH_aeqc_b') SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nph']) +SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## SYSTEMS["systemname"].append('Al18C2_NPH_onlyb') @@ -3495,3 +3495,4 @@ def WriteReport(data_info, systems, isparallel, ifVHQ, isorient): if failtests > 0: raise Exception(str(failtests) + " out of "+str(passtests+failtests) +" failed") + From 4848ac7d098e2ce72970869a023973d3eeae768f Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Mon, 6 Apr 2026 12:35:18 -0400 Subject: [PATCH 83/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- tests/SPARC_testing_script.py | 65 +++++++---------------------------- 1 file changed, 12 insertions(+), 53 deletions(-) diff --git a/tests/SPARC_testing_script.py b/tests/SPARC_testing_script.py index 242effd9..bb5a4f12 100644 --- a/tests/SPARC_testing_script.py +++ b/tests/SPARC_testing_script.py @@ -14,10 +14,10 @@ # Other parameters to run the test (can be changed by the user) nprocs_tests = 12 # In default tests are run with 24 processors per node nnodes_tests = 3 # In default tests are run with 1 node -npbs = 40 # By default (number of script files the tests are distributed to) +npbs = 10 # By default (number of script files the tests are distributed to) launch_cluster_extension = ".sbatch" # extension of the file used to launch the jobs on the cluster by default it is .sbatch command_launch_extension = "sbatch" # Command to launch the script to ask for resources on the cluster (example: qsub launch.pbs) -MPI_command = "mpirun -np 36" # MPI command to run the executable on the given cluster +MPI_command = "mpirun -np 48" # MPI command to run the executable on the given cluster @@ -215,71 +215,26 @@ SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nptnh']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################ -SYSTEMS["systemname"].append('Al18Si18_NPTNP') -SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nptnp']) -SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) -################################################################################################################ SYSTEMS["systemname"].append('Al16Si16_NPTNP_restart') SYSTEMS["directory"].append("./") SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## -SYSTEMS["systemname"].append('Al18Si18_NPTNP_aeqb_c') -SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) -SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) -################################################################################################################## -SYSTEMS["systemname"].append('Al18C2_NPTNP_onlyc') -SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) -SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) -################################################################################################################## SYSTEMS["systemname"].append('Al18C2_NPTNP_aeqb_ortho_c') SYSTEMS["directory"].append("./") SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## -SYSTEMS["systemname"].append('Al18C2_NPTNP_ortho_c') -SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nptnp']) -SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) -################################################################################################################## SYSTEMS["systemname"].append('Al18C2_NPTNP_full_flex') SYSTEMS["directory"].append("./") SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nptnp']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################ -SYSTEMS["systemname"].append('Al18Si18_NPH') -SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nph']) -SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) -################################################################################################################ SYSTEMS["systemname"].append('Al16Si16_NPH_restart') SYSTEMS["directory"].append("./") SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) ################################################################################################################## -SYSTEMS["systemname"].append('Al18Si18_NPH_aeqc_b') -SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) -SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) -################################################################################################################## -SYSTEMS["systemname"].append('Al18C2_NPH_onlyb') -SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) -SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) -################################################################################################################## -SYSTEMS["systemname"].append('Al18C2_NPH_beqc_ortho_a') -SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) -SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) -################################################################################################################## -SYSTEMS["systemname"].append('Al18C2_NPH_ortho_a') -SYSTEMS["directory"].append("./") -SYSTEMS["Tags"].append(['bulk', 'gga', 'orth', 'md_nph']) -SYSTEMS["Tols"].append([tols["E_tol"], tols["F_tol"], tols["stress_tol"]]) # E_tol(Ha/atom), F_tol(Ha/Bohr), stress_tol(%) -################################################################################################################## SYSTEMS["systemname"].append('Al18C2_NPH_full_flex') SYSTEMS["directory"].append("./") SYSTEMS["Tags"].append(['bulk', 'gga', 'nonorth', 'md_nph']) @@ -738,7 +693,7 @@ def launchsystems(systems, dirs_sys, memcheck, procs_nodes_cluster, ismempbs, if # os.system("cp *.psp8 temp_run") if ismlff_copy[countx] == True: os.system("cp ./high_accuracy/MLFF* ./temp_run") - if syst == "Al16Si16_NPTNH_restart" or syst == "Al16Si16_NPTNP_restart": + if syst == "Al16Si16_NPTNH_restart" or syst == "Al16Si16_NPTNP_restart" or syst == "Al16Si16_NPH_restart": os.system("cp ./standard/*.restart ./temp_run") if ifVHQ == False: os.system("cp ./standard/*.inpt ./temp_run") @@ -746,7 +701,7 @@ def launchsystems(systems, dirs_sys, memcheck, procs_nodes_cluster, ismempbs, if # os.system("cp *.psp8 temp_run") if ismlff_copy[countx] == True: os.system("cp ./standard/MLFF* ./temp_run") - if syst == "Al16Si16_NPTNH_restart" or syst == "Al16Si16_NPTNP_restart": + if syst == "Al16Si16_NPTNH_restart" or syst == "Al16Si16_NPTNP_restart" or syst == "Al16Si16_NPH_restart": os.system("cp ./standard/*.restart ./temp_run") else: os.mkdir("temp_run") @@ -757,7 +712,7 @@ def launchsystems(systems, dirs_sys, memcheck, procs_nodes_cluster, ismempbs, if # os.system("cp *.psp8 temp_run") if ismlff_copy[countx] == True: os.system("cp ./high_accuracy/MLFF* ./temp_run") - if syst == "Al16Si16_NPTNH_restart" or syst == "Al16Si16_NPTNP_restart": + if syst == "Al16Si16_NPTNH_restart" or syst == "Al16Si16_NPTNP_restart" or syst == "Al16Si16_NPH_restart": os.system("cp ./standard/*.restart ./temp_run") if ifVHQ == False: os.system("cp ./standard/*.inpt ./temp_run") @@ -765,7 +720,7 @@ def launchsystems(systems, dirs_sys, memcheck, procs_nodes_cluster, ismempbs, if # os.system("cp *.psp8 temp_run") if ismlff_copy[countx] == True: os.system("cp ./standard/MLFF* ./temp_run") - if syst == "Al16Si16_NPTNH_restart" or syst == "Al16Si16_NPTNP_restart": + if syst == "Al16Si16_NPTNH_restart" or syst == "Al16Si16_NPTNP_restart" or syst == "Al16Si16_NPH_restart": os.system("cp ./standard/*.restart ./temp_run") else: if os.path.isdir("temp_run1"): @@ -2573,7 +2528,11 @@ def WriteReport(data_info, systems, isparallel, ifVHQ, isorient): text1="Memory leak check valgrind: "+"\n"+"Total memory lost: "+str(memlost)+" Bytes \n" if len(info_run["energy"]) != len(info_ref["energy"]): test_status.append("failed") - text = "System name: "+systems[i]+"\n"+"different number of MD iterations from the hence failed!" + text = "System name: "+systems[i]+"\n"+"different number of MD iterations from reference hence failed!" + texttoprint.append(text) + Error_message_global.append("MD iteration count mismatch with reference") + Warning_message_global.append("") + else: E_ref = info_ref["energy"] E_run = info_run["energy"] @@ -3209,7 +3168,7 @@ def WriteReport(data_info, systems, isparallel, ifVHQ, isorient): elif ("relax_total_nlcg" in tags_sys[i]) or ("relax_total_lbfgs" in tags_sys[i]) or ("relax_total_fire" in tags_sys[i]): singlept.append(False) Type.append("relax_total") - elif ("md_nve" in tags_sys[i]) or ("md_nvtnh" in tags_sys[i]) or ("md_nvkg" in tags_sys[i]) or ("md_npt" in tags_sys[i]): + elif ("md_nve" in tags_sys[i]) or ("md_nvtnh" in tags_sys[i]) or ("md_nvkg" in tags_sys[i]) or ("md_nptnh" in tags_sys[i]) or ("md_nptnp" in tags_sys[i]) or ("md_nph" in tags_sys[i]): singlept.append(False) Type.append("MD") else: From b2ad24e38e67296081ea4beacfd212e7cd994de7 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Mon, 6 Apr 2026 12:36:11 -0400 Subject: [PATCH 84/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index da7c0dcd..2c3f0081 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,7 @@ -changes -------------- -April 05, 2026 +April 06, 2026 Name: Shubhang Krishnakant Trivedi Changes: (src/md.c, src/initialization.c, src/readfiles.c, src/include/md.h, src/include/isddft.h) 1. Extended the functionality of NPT_NP QMD for doing full cell flexibility (including changing of cell angles). From fbccff8c37659e2d21fb7f05a04f9eb6d624acff Mon Sep 17 00:00:00 2001 From: Shubhang Krishnakant Trivedi Date: Mon, 6 Apr 2026 18:38:41 -0400 Subject: [PATCH 85/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- .../high_accuracy/Al16Si16_NPH_restart.inpt} | 25 +- .../high_accuracy/Al16Si16_NPH_restart.ion | 53 + .../Al16Si16_NPH_restart.refaimd | 1517 ++++++++++ .../high_accuracy/Al16Si16_NPH_restart.refout | 597 ++++ .../Al16Si16_NPH_restart.restart | 128 + .../high_accuracy/Reports/Report-6294427.out | 30 + .../high_accuracy/Reports/Report-6294460.out | 30 + .../standard/Al16Si16_NPH_restart.inpt} | 25 +- .../standard/Al16Si16_NPH_restart.ion | 53 + .../standard/Al16Si16_NPH_restart.refaimd | 1517 ++++++++++ .../standard/Al16Si16_NPH_restart.refout | 587 ++++ .../standard/Al16Si16_NPH_restart.restart | 128 + .../high_accuracy/Al16Si16_NPTNP_restart.inpt | 4 +- .../Al16Si16_NPTNP_restart.refaimd | 2613 +++++++++-------- .../Al16Si16_NPTNP_restart.refout | 688 ++--- .../Al16Si16_NPTNP_restart.restart | 203 +- .../standard/Al16Si16_NPTNP_restart.inpt | 4 +- .../standard/Al16Si16_NPTNP_restart.refaimd | 2613 +++++++++-------- .../standard/Al16Si16_NPTNP_restart.refout | 675 ++--- .../standard/Al16Si16_NPTNP_restart.restart | 203 +- .../high_accuracy/Al18C2_NPH_full_flex.inpt | 45 + .../high_accuracy/Al18C2_NPH_full_flex.ion} | 0 .../Al18C2_NPH_full_flex.refaimd | 1157 ++++++++ .../high_accuracy/Al18C2_NPH_full_flex.refout | 653 ++++ .../standard/Al18C2_NPH_full_flex.inpt | 45 + .../standard/Al18C2_NPH_full_flex.ion} | 0 .../standard/Al18C2_NPH_full_flex.refaimd | 1157 ++++++++ .../standard/Al18C2_NPH_full_flex.refout | 647 ++++ .../high_accuracy/Al18C2_NPTNP_aeqb_c.refaimd | 939 ------ .../high_accuracy/Al18C2_NPTNP_aeqb_c.refout | 606 ---- .../standard/Al18C2_NPTNP_aeqb_c.refaimd | 939 ------ .../standard/Al18C2_NPTNP_aeqb_c.refout | 600 ---- .../Al18C2_NPTNP_aeqb_ortho_c.inpt} | 8 +- .../Al18C2_NPTNP_aeqb_ortho_c.ion} | 0 .../Al18C2_NPTNP_aeqb_ortho_c.refaimd | 1168 ++++++++ .../Al18C2_NPTNP_aeqb_ortho_c.refout | 649 ++++ .../standard/Al18C2_NPTNP_aeqb_ortho_c.inpt} | 13 +- .../standard/Al18C2_NPTNP_aeqb_ortho_c.ion} | 0 .../Al18C2_NPTNP_aeqb_ortho_c.refaimd | 1168 ++++++++ .../standard/Al18C2_NPTNP_aeqb_ortho_c.refout | 653 ++++ .../high_accuracy/Al18C2_NPTNP_full_flex.inpt | 45 + .../high_accuracy/Al18C2_NPTNP_full_flex.ion | 41 + .../Al18C2_NPTNP_full_flex.refaimd | 1168 ++++++++ .../Al18C2_NPTNP_full_flex.refout | 655 +++++ .../standard/Al18C2_NPTNP_full_flex.inpt | 45 + .../standard/Al18C2_NPTNP_full_flex.ion | 41 + .../standard/Al18C2_NPTNP_full_flex.refaimd | 1168 ++++++++ .../standard/Al18C2_NPTNP_full_flex.refout | 648 ++++ .../high_accuracy/Al18C2_NPTNP_onlyc.refaimd | 939 ------ .../high_accuracy/Al18C2_NPTNP_onlyc.refout | 572 ---- .../standard/Al18C2_NPTNP_onlyc.refaimd | 939 ------ .../standard/Al18C2_NPTNP_onlyc.refout | 566 ---- .../high_accuracy/Al18Si18_NPTNP.inpt | 38 - .../high_accuracy/Al18Si18_NPTNP.ion | 63 - .../high_accuracy/Al18Si18_NPTNP.refaimd | 1419 --------- .../high_accuracy/Al18Si18_NPTNP.refout | 573 ---- .../standard/Al18Si18_NPTNP.inpt | 38 - .../standard/Al18Si18_NPTNP.ion | 63 - .../standard/Al18Si18_NPTNP.refaimd | 1419 --------- .../standard/Al18Si18_NPTNP.refout | 551 ---- .../Al18Si18_NPTNP/standard/esparallel.sbatch | 18 - tests/SPARC_testing_script.py | 2 +- 62 files changed, 19629 insertions(+), 13522 deletions(-) rename tests/{Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.inpt => Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.inpt} (72%) create mode 100644 tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.ion create mode 100644 tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.refaimd create mode 100644 tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.refout create mode 100644 tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.restart create mode 100644 tests/Al16Si16_NPH_restart/high_accuracy/Reports/Report-6294427.out create mode 100644 tests/Al16Si16_NPH_restart/high_accuracy/Reports/Report-6294460.out rename tests/{Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.inpt => Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.inpt} (72%) create mode 100644 tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.ion create mode 100644 tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.refaimd create mode 100644 tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.refout create mode 100644 tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.restart create mode 100644 tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.inpt rename tests/{Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.ion => Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.ion} (100%) create mode 100644 tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.refaimd create mode 100644 tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.refout create mode 100644 tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.inpt rename tests/{Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.ion => Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.ion} (100%) create mode 100644 tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.refaimd create mode 100644 tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.refout delete mode 100644 tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.refaimd delete mode 100644 tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.refout delete mode 100644 tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.refaimd delete mode 100644 tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.refout rename tests/{Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.inpt => Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.inpt} (92%) rename tests/{Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.ion => Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.ion} (100%) create mode 100644 tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.refaimd create mode 100644 tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.refout rename tests/{Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.inpt => Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.inpt} (88%) rename tests/{Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.ion => Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.ion} (100%) create mode 100644 tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.refaimd create mode 100644 tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.refout create mode 100644 tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.inpt create mode 100644 tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.ion create mode 100644 tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.refaimd create mode 100644 tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.refout create mode 100644 tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.inpt create mode 100644 tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.ion create mode 100644 tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.refaimd create mode 100644 tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.refout delete mode 100644 tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.refaimd delete mode 100644 tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.refout delete mode 100644 tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.refaimd delete mode 100644 tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.refout delete mode 100644 tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.inpt delete mode 100644 tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.ion delete mode 100644 tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.refaimd delete mode 100644 tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.refout delete mode 100644 tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.inpt delete mode 100644 tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.ion delete mode 100644 tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.refaimd delete mode 100644 tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.refout delete mode 100644 tests/Al18Si18_NPTNP/standard/esparallel.sbatch diff --git a/tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.inpt b/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.inpt similarity index 72% rename from tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.inpt rename to tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.inpt index 2820e3c2..8d8ebd76 100644 --- a/tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.inpt +++ b/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.inpt @@ -1,14 +1,15 @@ -# nprocs: 48 -LATVEC_SCALE: 13.322568219 17.479965394 13.020212061 +# nprocs: 24 +LATVEC_SCALE: 15 15 15 LATVEC: 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 -MESH_SPACING: 0.15 +MESH_SPACING: 0.2 BC: P P P KPOINT_GRID: 1 1 1 +# SPIN_TYP: 1 EXCHANGE_CORRELATION: GGA_PBE -TOL_SCF: 1e-6 +TOL_SCF: 5e-7 # TOL_POISSON: 1e-7 # TOL_PSEUDOCHARGE: 1e-5 MIXING_PARAMETER: 1.0 @@ -18,21 +19,21 @@ PRECOND_KERKER_THRESH: 0 # MD MD_FLAG: 1 # 1 = MD, 0 = no MD (default) -ION_TEMP: 2400 # kelvin +ION_TEMP: 1120 # kelvin # ION_TEMP_END: 1120 -MD_METHOD: NPT_NP # NVE, NVT_NH (Nose-Hoover), NVK_G (Gaussian) +MD_METHOD: NPH # NVE, NVT_NH (Nose-Hoover), NVK_G (Gaussian) #QMASS: 1600 # mass for NH thermostat -MD_TIMESTEP: 1 # fs +MD_TIMESTEP: 0.6 # fs MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whichever comes first #TWTIME: 1400 RESTART_FLAG: 1 # 1 = restart MD from .restart file if present, 0 = start new #ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) -TARGET_PRESSURE: 0.1 GPa -NPT_NP_QMASS: 20000 -NPT_NP_BMASS: 1000 -NPT_SCALE_VECS: 3 +EXTERNAL_PRESSURE: 0 GPa +#NPT_NP_QMASS: 500.0 +NPH_BMASS: 0.1 +NPH_SCALE_CONSTRAINTS: 123 -NSTATES: 72 +NSTATES: 76 # outputs # CALC_PRES: 1 diff --git a/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.ion b/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.ion new file mode 100644 index 00000000..79360080 --- /dev/null +++ b/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.ion @@ -0,0 +1,53 @@ +#CELL: 15 15 15 +#LATVEC +# 1.000000000000000 0.000000000000000 0.000000000000000 +# 0.000000000000000 1.000000000000000 0.000000000000000 +# 0.100000000000000 0.100000000000000 0.900000000000000 +#PBC: True True True +# + + +ATOM_TYPE: Al # atom type followed with valence charge +N_TYPE_ATOM: 16 # number of atoms of this type +PSEUDO_POT: ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +ATOMIC_MASS: 26.9815385 +COORD: # coordinates follows +0.4 0 0 +3.75 0 3.75 +7.5 0 0.3 +11.25 0 3.75 +0 7.5 0 +3.75 7.5 3.75 +7.5 7.5 0 +11.25 7.5 3.75 +0.4 0 7.5 +3.75 0 11.25 +7.5 0 7.8 +11.25 0 11.25 +0 7.5 7.5 +3.75 7.5 11.25 +7.5 7.5 7.5 +11.25 7.5 11.25 + + +ATOM_TYPE: Si # atom type followed with valence charge +N_TYPE_ATOM: 16 # number of atoms of this type +PSEUDO_POT: ../../../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 +ATOMIC_MASS: 28.085 +COORD: # coordinates follows +0 3.75 3.75 +3.75 3.75 0 +7.5 3.75 3.75 +11.25 3.75 0 +0.3 11.25 3.75 +3.75 11.25 0.5 +7.5 11.25 3.75 +11.25 11.25 0 +0 3.75 11.25 +3.75 3.75 7.5 +7.5 3.75 11.25 +11.25 3.75 7.5 +0.3 11.25 11.25 +3.75 11.25 8 +7.5 11.25 11.25 +11.25 11.25 7.5 diff --git a/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.refaimd b/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.refaimd new file mode 100644 index 00000000..9980665f --- /dev/null +++ b/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.refaimd @@ -0,0 +1,1517 @@ +:Description: + +:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr +:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu + where atu is the atomic unit of time, hbar/Ha +:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr +:Desc_MDTM: MD time. Unit=second +:Desc_TEL: Electronic temperature. Unit=Kelvin +:Desc_TIO: Ionic temperature. Unit=Kelvin +:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom +:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom +:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom + where N = number of particles, k = Boltzmann constant +:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom +:Desc_UEN: Internal energy. Unit=Ha/atom +:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom +:Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree +:Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 +:Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 +:Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during NPH ensemble (has same magnitude as initial LatVec). Unit = Bohr +:Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha +:Desc_NPH_Enthalpy: Enthalpy of the NPH system (or generalized enthalpy in case of anisotropic stress). This quantity is same as NPH Hamiltonian (NPH_HAMIL) plus the initial NPH hamiltonian. Unit = Ha +:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa +:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa +:Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa +:Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa +:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa + where N = number of particles, k = Boltzmann constant, V = volume +:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr + + + + +:MDSTEP: 21 +:MDTM: 45.44 +:TWIST: 0 +:TEL: 1120 +:TIO: 1132.53450606554 +:TEN: -3.2406181320E+00 +:KEN: 5.2116667718E-03 +:KENIG: 5.3797850547E-03 +:FEN: -3.2458297987E+00 +:UEN: -3.2449003133E+00 +:TSEN: -9.2948545106E-04 +:NPH_HAMIL: -4.1388142549E-05 +:NPH_ENTHALPY: -1.0368216788E+02 +:R: + 3.7821386612E-01 2.7610243971E-01 1.5877961297E-01 + 3.8306488250E+00 1.5184616989E+01 3.9859888361E+00 + 7.8282405005E+00 1.5074999344E+01 1.7563133011E-01 + 1.1293130908E+01 1.5189362369E+01 3.6481797039E+00 + 1.0436087852E-01 7.7713969978E+00 1.5192768445E+01 + 3.7321556689E+00 7.7628257450E+00 3.7783632147E+00 + 7.3190243007E+00 7.4168571310E+00 1.0285052253E-01 + 1.1415089306E+01 7.6739189176E+00 3.9386631094E+00 + 5.3229358748E-01 1.5066269254E+01 7.6519541746E+00 + 3.6530763425E+00 2.2842110153E-02 1.1191072798E+01 + 7.6121790176E+00 3.4856691517E-02 7.7850637292E+00 + 1.1445840575E+01 1.5068900197E+01 1.1568578988E+01 + 2.0176186061E-01 7.6158114362E+00 7.7412941179E+00 + 4.0760765696E+00 7.7499802251E+00 1.1381611206E+01 + 7.3492936068E+00 7.8332635406E+00 7.5012979993E+00 + 1.1418485849E+01 7.3193908223E+00 1.1383528878E+01 + 5.8239803863E-02 3.8678991419E+00 3.8703576117E+00 + 3.7226279205E+00 3.8211142119E+00 1.5203493003E+01 + 7.7131027467E+00 3.6601887305E+00 3.5222994422E+00 + 1.1317801763E+01 3.7738423895E+00 1.5097012359E+01 + 3.0429600490E-01 1.1342919572E+01 3.8577886293E+00 + 3.6493334170E+00 1.1438569231E+01 4.8043006716E-01 + 7.7087343844E+00 1.1530457410E+01 3.8253060061E+00 + 1.1099755188E+01 1.1393487696E+01 4.2523023204E-02 + 9.5147217373E-02 3.7066161661E+00 1.1222982683E+01 + 3.7963361440E+00 3.7030249293E+00 7.7924678577E+00 + 7.7618427489E+00 3.7504643080E+00 1.1424711522E+01 + 1.1301155961E+01 3.8912676307E+00 7.6991262943E+00 + 2.8982176377E-01 1.1408607979E+01 1.1414432425E+01 + 3.7181667005E+00 1.1215602612E+01 7.8651608433E+00 + 7.7071413220E+00 1.1564720398E+01 1.1550133754E+01 + 1.1489551803E+01 1.1416599349E+01 7.6960714288E+00 +:V: + -8.2484024316E-05 5.3322159299E-04 3.1233139310E-04 + 1.0097447533E-04 -3.8789079378E-05 3.4846735334E-04 + 4.0616766598E-04 -2.5345482721E-04 -2.8300123455E-04 + -1.9524360879E-04 -3.8226844692E-05 -2.7473333942E-04 + 2.0651428238E-04 3.0684264410E-04 -3.2737276000E-05 + -1.4898524157E-04 3.1369759913E-04 -4.0315157647E-05 + -5.2939375961E-04 -3.5906174232E-04 2.1488492313E-04 + 1.3246274480E-05 1.3406019729E-04 2.6001905366E-04 + 1.6651537896E-04 -2.7551876638E-04 7.3733761015E-05 + -2.4885951254E-04 4.6930996525E-05 -3.8188090281E-04 + 2.4935693122E-05 6.5135863718E-05 -2.4985706571E-04 + 9.8067030289E-05 -2.6741028192E-04 3.2705580687E-04 + 4.0239642575E-04 3.1356611179E-05 2.7463143630E-04 + 5.1549517828E-04 2.6706353187E-04 -5.2353499216E-05 + -4.8421802470E-04 4.3517644666E-04 -1.9445528185E-04 + 1.0291171228E-05 -5.7444475575E-04 -3.6978297640E-05 + 1.3364723696E-04 1.1744125545E-04 1.3276116314E-04 + -1.7132767201E-04 3.9547442387E-05 4.3978131523E-05 + 2.3840840655E-04 -2.8403543355E-04 -6.1566621053E-04 + -2.3371703087E-04 -2.3492838089E-05 -2.2165540378E-04 + 8.6134627984E-05 -1.3228421071E-04 9.5598283698E-05 + -3.1880444601E-04 5.7936313179E-05 1.3624789691E-05 + 2.4600772147E-04 2.4137364301E-04 -4.0610408937E-05 + -7.0989630764E-04 -3.8056875095E-06 1.3421942335E-04 + 2.0387592075E-04 -1.7686004965E-04 -4.0477501175E-04 + -5.1430267964E-05 -1.9721714858E-04 4.3356226488E-04 + 3.6770548877E-04 -9.0755378460E-05 1.4070693283E-05 + -2.1643726597E-04 1.7139946327E-04 2.1101947683E-04 + 2.3307705790E-05 1.4150318247E-05 -5.3323978752E-05 + -2.5950294591E-04 -3.8111496802E-04 -4.7377254245E-04 + 2.8884936132E-04 3.1180510176E-04 2.2729660057E-04 + 1.2779550769E-04 2.2164309138E-05 2.4926552473E-04 +:F: + -3.3251749877E-03 -4.2968983689E-03 -1.0273297855E-03 + 1.0254231207E-02 8.6546904118E-04 -4.8804008602E-03 + -1.2216787851E-02 2.7397460183E-03 -6.1914055211E-03 + 7.4483576931E-03 -1.0493459512E-03 7.5056771281E-03 + -1.2238561544E-03 -6.0241085958E-03 -4.3290062225E-04 + -3.0009471914E-03 9.2697457390E-04 1.5422531938E-03 + 9.5235347541E-03 3.7765645597E-03 1.1651270506E-03 + -3.3723150929E-04 3.5626006267E-04 -1.8347739172E-03 + -2.0199435196E-02 6.4405521409E-04 -6.9178700323E-03 + 1.1771941410E-02 -1.5522904780E-03 1.2900661805E-02 + 1.6063726619E-03 -5.9608117591E-04 8.3172502231E-04 + 5.3099741177E-03 9.1616002476E-04 -4.1401063279E-04 + -1.4784884081E-03 2.3472220903E-03 6.1524393103E-04 + -6.3772746828E-03 -5.1214903319E-03 4.5254197137E-04 + 7.0988822067E-03 -4.9040831520E-03 1.9207536092E-04 + -2.3988313412E-03 -1.5267018338E-03 2.2623246991E-03 + 7.3135008973E-03 -2.7141491628E-03 -1.5351860148E-03 + -4.2999157023E-03 2.9119381582E-04 1.1181744612E-02 + 2.7876846987E-03 -2.3311848748E-03 -1.4234694915E-02 + -1.5485634435E-02 9.5500424482E-03 1.0086876593E-03 + 2.0418389878E-02 -2.4593210291E-03 6.9249996248E-04 + -1.1365711856E-03 -4.3188817580E-04 1.4822585505E-02 + 5.4190472706E-03 -1.2469088490E-03 -1.7040983620E-02 + -2.2225042215E-02 4.1361747932E-03 7.0788801410E-03 + 3.4242009905E-03 3.3582196318E-03 -1.1607497089E-02 + -1.0526355166E-02 -8.8391900216E-04 1.0979492931E-02 + 1.3397554076E-02 2.4953446313E-03 -4.3719639869E-03 + -1.7190137299E-03 -2.0044947027E-03 9.2694248164E-03 + 1.0460650542E-02 3.4902638825E-03 -1.3912653055E-02 + -2.3550794291E-02 1.2593497855E-03 -8.8912310574E-04 + 1.8600728008E-02 3.3172832195E-04 -9.2298615001E-03 + -5.3336963631E-03 -3.4190321135E-04 1.2019708869E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5174948748E+03 +:LATVEC_SCALE: + 1.5208200323E+01 1.5208200323E+01 1.5208200323E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 1.0711545810E+00 -2.3372445801E-03 1.2612061944E-02 + -2.3372445801E-03 8.1649211945E-01 1.7708771959E-01 + 1.2612061944E-02 1.7708771959E-01 9.0220296884E-01 +:STRESS: + -3.4876435924E+00 -3.1588852343E-01 1.2139499520E+00 + -3.1588852343E-01 1.3129013542E+00 4.4228410589E-02 + 1.2139499520E+00 4.4228410589E-02 -2.7267446611E+00 +:CONSTRESS: + 4.0315870866E+00 6.1748365240E-01 -2.3590010051E+00 + 6.1748365240E-01 -6.2587079613E+00 2.6468600997E-01 + -2.3590010051E+00 2.6468600997E-01 2.2271208747E+00 +:TOTSTRESS: + 5.2721108690E-01 -3.0393237355E-01 1.1576631151E+00 + -3.0393237355E-01 5.7622987265E+00 -1.3182670096E-01 + 1.1576631151E+00 -1.3182670096E-01 1.4018267553E+00 +:PRESIO: 9.2994988978E-01 +:PRES: 1.6338289664E+00 +:CONPRES: -5.3163881891E-16 +:TOTPRES: 2.5637788562E+00 +:PRESIG: 9.5994827332E-01 +:MIND: +Al - Al: 4.7214188371E+00 +Si - Si: 4.7544689507E+00 +Al - Si: 4.8763656353E+00 + + +:MDSTEP: 22 +:MDTM: 15.18 +:TWIST: 0 +:TEL: 1120 +:TIO: 1134.10920093666 +:TEN: -3.2406524993E+00 +:KEN: 5.2189131602E-03 +:KENIG: 5.3872651976E-03 +:FEN: -3.2458714125E+00 +:UEN: -3.2449630638E+00 +:TSEN: -9.0834869289E-04 +:NPH_HAMIL: -5.5629362123E-05 +:NPH_ENTHALPY: -1.0368218213E+02 +:R: + 3.7660813159E-01 2.8965664562E-01 1.6672462642E-01 + 3.8379162178E+00 1.5202271751E+01 3.9994984000E+00 + 7.8478467946E+00 1.5087200206E+01 1.6877943771E-01 + 1.1302171288E+01 1.5207024920E+01 3.6458754313E+00 + 1.0960996483E-01 7.7885056375E+00 1.5210575366E+01 + 3.7330115156E+00 7.7801376539E+00 3.7820029989E+00 + 7.3149076852E+00 7.4170546792E+00 1.0832060529E-01 + 1.1429408315E+01 7.6866569381E+00 3.9499371028E+00 + 5.3695499967E-01 1.5077898328E+01 7.6631214966E+00 + 3.6514473719E+00 2.4025929890E-02 1.1195387045E+01 + 7.6221390567E+00 3.6513348532E-02 7.7884062910E+00 + 1.1462339186E+01 1.5080735576E+01 1.1590879189E+01 + 2.1199352024E-01 7.6259400323E+00 7.7576074649E+00 + 4.0938353594E+00 7.7660803423E+00 1.1394264939E+01 + 7.3463208595E+00 7.8536422272E+00 7.5056646429E+00 + 1.1432722720E+01 7.3140866022E+00 1.1396578142E+01 + 6.1674352775E-02 3.8755406043E+00 3.8783896542E+00 + 3.7229101324E+00 3.8267818981E+00 1.5223288300E+01 + 7.7284948496E+00 3.6576071287E+00 3.5112410784E+00 + 1.1325777074E+01 3.7779422173E+00 1.5110018861E+01 + 3.0693101767E-01 1.1353523151E+01 3.8648957193E+00 + 3.6458822001E+00 1.1454026421E+01 4.8144651255E-01 + 7.7243256949E+00 1.1550578037E+01 3.8288838138E+00 + 1.1095596658E+01 1.1407383734E+01 4.5951105931E-02 + 1.0034775155E-01 3.7067874283E+00 1.1226616837E+01 + 3.7996489228E+00 3.7026606937E+00 7.8128532194E+00 + 7.7805695516E+00 3.7528225552E+00 1.1439038608E+01 + 1.1309622841E+01 3.9002820712E+00 7.7138600522E+00 + 2.9081880346E-01 1.1422964606E+01 1.1427015748E+01 + 3.7161377691E+00 1.1219892735E+01 7.8630300347E+00 + 7.7238739686E+00 1.1586641703E+01 1.1569880864E+01 + 1.1506776963E+01 1.1431141745E+01 7.7117678384E+00 +:V: + -8.3980333448E-05 5.3035049505E-04 3.1141492924E-04 + 1.0605414496E-04 -3.8333077697E-05 3.4553081711E-04 + 3.9932635698E-04 -2.5170775795E-04 -2.8579481574E-04 + -1.9117525372E-04 -3.8725520669E-05 -2.7054521474E-04 + 2.0561228117E-04 3.0341033711E-04 -3.2911171076E-05 + -1.5034365686E-04 3.1380812872E-04 -3.9512828371E-05 + -5.2389131348E-04 -3.5667954790E-04 2.1515827161E-04 + 1.3092853292E-05 1.3411601900E-04 2.5881267167E-04 + 1.5600654084E-04 -2.7488813550E-04 7.0063656349E-05 + -2.4251848213E-04 4.6008390161E-05 -3.7474351310E-04 + 2.5706208990E-05 6.4795802375E-05 -2.4905363498E-04 + 1.0069671104E-04 -2.6664988526E-04 3.2637811079E-04 + 4.0105762329E-04 3.2512411567E-05 2.7459784488E-04 + 5.1165359999E-04 2.6413541371E-04 -5.1992081635E-05 + -4.7992461483E-04 4.3211844665E-04 -1.9418782003E-04 + 9.1114551638E-06 -5.7447708679E-04 -3.5776436545E-05 + 1.3714308528E-04 1.1601128024E-04 1.3180875171E-04 + -1.7325231475E-04 3.9656229180E-05 4.9336925509E-05 + 2.3939161869E-04 -2.8488760243E-04 -6.2179418244E-04 + -2.4101804634E-04 -1.8763691708E-05 -2.2087757363E-04 + 9.5947557531E-05 -1.3334868892E-04 9.5888838334E-05 + -3.1889806522E-04 5.7686985901E-05 2.0819308017E-05 + 2.4821836188E-04 2.4045649024E-04 -4.8769906010E-05 + -7.1969949683E-04 -1.8610553552E-06 1.3739968944E-04 + 2.0523407109E-04 -1.7499514531E-04 -4.0994175962E-04 + -5.6485634399E-05 -1.9740635371E-04 4.3823245228E-04 + 3.7378505847E-04 -8.9458472202E-05 1.1950593331E-05 + -2.1701506620E-04 1.7017131980E-04 2.1536684128E-04 + 2.8312832181E-05 1.5890807345E-05 -5.9965102690E-05 + -2.7068836633E-04 -3.7993413496E-04 -4.7370761417E-04 + 2.9747356894E-04 3.1161288469E-04 2.2260576438E-04 + 1.2514399274E-04 2.1939458931E-05 2.5471587636E-04 +:F: + -3.0132839636E-03 -4.5054789423E-03 -1.0919709666E-03 + 1.0393041643E-02 7.5563681310E-04 -5.0791908930E-03 + -1.2956833559E-02 2.9614376904E-03 -6.2686846869E-03 + 7.7467490241E-03 -1.1151349087E-03 7.7785443923E-03 + -1.3520778806E-03 -6.1050550968E-03 -4.1618743011E-04 + -3.1131349213E-03 1.0355056579E-03 1.4457059028E-03 + 9.7389823727E-03 3.9318821836E-03 9.6359637109E-04 + -2.0729355285E-04 5.1641755007E-04 -1.6892248001E-03 + -2.0691829803E-02 5.1997349073E-04 -7.2871790386E-03 + 1.2180915814E-02 -1.8805444061E-03 1.3565879727E-02 + 1.5722983838E-03 -4.3699448577E-04 1.1423959110E-03 + 5.6011911170E-03 8.0218198546E-04 -6.8616836197E-04 + -1.8789657224E-03 2.3914554566E-03 5.8564476497E-04 + -6.3623531904E-03 -5.2002325744E-03 7.2710956676E-04 + 7.5853130442E-03 -5.1162504694E-03 -7.5254951241E-05 + -2.2325499135E-03 -1.3923404464E-03 2.3271428225E-03 + 7.8013391664E-03 -2.5984557043E-03 -1.7272228166E-03 + -4.5158893647E-03 3.5808005887E-04 1.1174718227E-02 + 2.4791443000E-03 -2.6247337953E-03 -1.4189675641E-02 + -1.5852244587E-02 9.8643334576E-03 1.0831873700E-03 + 2.0548615970E-02 -2.6062537282E-03 9.9084219761E-04 + -8.6238236940E-04 -3.0504945897E-04 1.4962613513E-02 + 4.9560990691E-03 -1.3207184167E-03 -1.6866634483E-02 + -2.1856214115E-02 3.8768889339E-03 6.7358747405E-03 + 3.2165982902E-03 3.4502352654E-03 -1.1780066578E-02 + -1.0614449165E-02 -8.9483937880E-04 1.0503033094E-02 + 1.3572896674E-02 2.4025579589E-03 -4.3138253122E-03 + -1.7619766776E-03 -2.2014181328E-03 9.7537856213E-03 + 1.0330567502E-02 3.7700710753E-03 -1.3787703504E-02 + -2.3961676357E-02 1.6905389614E-03 -1.2382082521E-03 + 1.8481576672E-02 4.5096656187E-04 -8.9960381076E-03 + -4.9721738997E-03 -4.7466315602E-04 1.1753161601E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5304455373E+03 +:LATVEC_SCALE: + 1.5226841909E+01 1.5226841909E+01 1.5226841909E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0729027674E+00 1.9290955568E-04 6.8040830443E-03 + 1.9290955568E-04 8.0727573513E-01 1.7634032667E-01 + 6.8040830443E-03 1.7634032667E-01 9.0330204134E-01 +:STRESS: + -3.2416072913E+00 -3.2159201941E-01 1.2439200393E+00 + -3.2159201941E-01 1.3472172452E+00 4.2476165038E-02 + 1.2439200393E+00 4.2476165038E-02 -2.4264195192E+00 +:CONSTRESS: + 3.9299699723E+00 6.3337251894E-01 -2.4311014857E+00 + 6.3337251894E-01 -5.9501437702E+00 2.6675436859E-01 + -2.4311014857E+00 2.6675436859E-01 2.0201737979E+00 +:TOTSTRESS: + 3.8454008648E-01 -3.1158758998E-01 1.1939855294E+00 + -3.1158758998E-01 5.4102022601E+00 -1.3289020696E-01 + 1.1939855294E+00 -1.3289020696E-01 1.3095477627E+00 +:PRESIO: 9.2782684797E-01 +:PRES: 1.4402698551E+00 +:CONPRES: 8.0543281066E-14 +:TOTPRES: 2.3680967031E+00 +:PRESIG: 9.5775674629E-01 +:MIND: +Al - Al: 4.7124177544E+00 +Si - Si: 4.7546213773E+00 +Al - Si: 4.8721644891E+00 + + +:MDSTEP: 23 +:MDTM: 15.55 +:TWIST: 0 +:TEL: 1120 +:TIO: 1135.74591673836 +:TEN: -3.2406851206E+00 +:KEN: 5.2264449549E-03 +:KENIG: 5.3950399534E-03 +:FEN: -3.2459115655E+00 +:UEN: -3.2450235089E+00 +:TSEN: -8.8805660840E-04 +:NPH_HAMIL: -7.2085467096E-05 +:NPH_ENTHALPY: -1.0368219858E+02 +:R: + 3.7497664907E-01 3.0316409469E-01 1.7466153632E-01 + 3.8454367407E+00 1.5220422666E+01 4.0130726558E+00 + 7.8675423613E+00 1.5099921003E+01 1.6185421621E-01 + 1.1311670404E+01 1.5225160343E+01 3.6437851081E+00 + 1.1484578103E-01 7.8057873971E+00 1.5228864032E+01 + 3.7339477723E+00 7.7977118595E+00 3.7857819458E+00 + 7.3111468503E+00 7.4175386699E+00 1.1380638812E-01 + 1.1444090661E+01 7.6996476248E+00 3.9613165957E+00 + 5.4137455214E-01 1.5090016442E+01 7.6744429412E+00 + 3.6500876908E+00 2.5186999503E-02 1.1200229355E+01 + 7.6323628394E+00 3.8165750169E-02 7.7920123270E+00 + 1.1479275008E+01 1.5093063627E+01 1.1613542136E+01 + 2.2220873624E-01 7.6363427589E+00 7.7741767231E+00 + 4.1116459153E+00 7.7823641647E+00 1.1407292540E+01 + 7.3436779567E+00 7.8742086016E+00 7.5102704987E+00 + 1.1447297665E+01 7.3089986762E+00 1.1410021401E+01 + 6.5204854116E-02 3.8832749666E+00 3.8865251833E+00 + 3.7232570660E+00 3.8325764415E+00 1.5243705490E+01 + 7.7441644014E+00 3.6551108298E+00 3.5001239147E+00 + 1.1333924058E+01 3.7822816840E+00 1.5123521993E+01 + 3.0982319270E-01 1.1364458762E+01 3.8721385436E+00 + 3.6425370916E+00 1.1469846697E+01 4.8265843389E-01 + 7.7402241329E+00 1.1571052759E+01 3.8323812129E+00 + 1.1091529823E+01 1.1421691641E+01 4.9461817078E-02 + 1.0559035936E-01 3.7071187516E+00 1.1230468363E+01 + 3.8029555842E+00 3.7024040856E+00 7.8336154332E+00 + 7.7997090640E+00 3.7553297954E+00 1.1453680028E+01 + 1.1318430445E+01 3.9093950224E+00 7.7289583084E+00 + 2.9194948388E-01 1.1437732329E+01 1.1439798966E+01 + 3.7139392763E+00 1.1224562130E+01 7.8611357113E+00 + 7.7410765184E+00 1.1608939629E+01 1.1589890315E+01 + 1.1524310789E+01 1.1446044426E+01 7.7278527678E+00 +:V: + -8.5317342472E-05 5.2736520397E-04 3.1045915895E-04 + 1.1118942687E-04 -3.7931759121E-05 3.4249048808E-04 + 3.9210855493E-04 -2.4983671846E-04 -2.8861406122E-04 + -1.8695635428E-04 -3.9253060919E-05 -2.6621638627E-04 + 2.0464396791E-04 2.9993653055E-04 -3.3075704338E-05 + -1.5174993652E-04 3.1396053551E-04 -3.8763917211E-05 + -5.1827846381E-04 -3.5421495251E-04 2.1532122404E-04 + 1.3005996572E-05 1.3424710197E-04 2.5767820096E-04 + 1.4526223120E-04 -2.7431525335E-04 6.6213442530E-05 + -2.3597413804E-04 4.4918845264E-05 -3.6726921687E-04 + 2.6458427859E-05 6.4538074218E-05 -2.4808777386E-04 + 1.0346897620E-04 -2.6593949190E-04 3.2555302871E-04 + 3.9950416512E-04 3.3684276330E-05 2.7454031840E-04 + 5.0781591725E-04 2.6116706769E-04 -5.1488160666E-05 + -4.7537811307E-04 4.2894411547E-04 -1.9405008862E-04 + 8.0198409502E-06 -5.7442170439E-04 -3.4543813334E-05 + 1.4086240430E-04 1.1463883034E-04 1.3075968009E-04 + -1.7527543345E-04 3.9798423028E-05 5.4681093266E-05 + 2.4022238060E-04 -2.8587133136E-04 -6.2786718402E-04 + -2.4847674219E-04 -1.3893908300E-05 -2.2005992991E-04 + 1.0579678419E-04 -1.3447698686E-04 9.6311634484E-05 + -3.1885357389E-04 5.7497360600E-05 2.8068560384E-05 + 2.5019520295E-04 2.3949630511E-04 -5.6830392619E-05 + -7.2927267490E-04 -5.2398529180E-08 1.4041286323E-04 + 2.0647871864E-04 -1.7308464669E-04 -4.1516241025E-04 + -6.1567376533E-05 -1.9759054548E-04 4.4264643168E-04 + 3.7992468853E-04 -8.8210427662E-05 9.8614158842E-06 + -2.1760919324E-04 1.6884341261E-04 2.1992357176E-04 + 3.3247645085E-05 1.7764962256E-05 -6.6533064216E-05 + -2.8204075181E-04 -3.7853167804E-04 -4.7378768781E-04 + 3.0600886219E-04 3.1146686598E-04 2.1802034519E-04 + 1.2266579164E-04 2.1648802992E-05 2.6002241678E-04 +:F: + -2.7105496473E-03 -4.7000653195E-03 -1.1501768586E-03 + 1.0512723973E-02 6.4608690664E-04 -5.2649568811E-03 + -1.3696159549E-02 3.2098343831E-03 -6.3415308470E-03 + 8.0426480008E-03 -1.1710235593E-03 8.0519126409E-03 + -1.4665871346E-03 -6.1690064451E-03 -4.0058377171E-04 + -3.2157393068E-03 1.1316297982E-03 1.3294639327E-03 + 9.9253960064E-03 4.0721614714E-03 7.5441127454E-04 + -7.2267909731E-05 6.7139688008E-04 -1.5240824110E-03 + -2.1166667496E-02 3.8478310026E-04 -7.6421649478E-03 + 1.2580605741E-02 -2.2137043302E-03 1.4227376832E-02 + 1.5406622928E-03 -2.6321956253E-04 1.4501275733E-03 + 5.9008720187E-03 6.8924951823E-04 -9.6274582310E-04 + -2.2883837931E-03 2.4205918665E-03 5.5329122090E-04 + -6.3188880812E-03 -5.2636078769E-03 1.0135054240E-03 + 8.0663073849E-03 -5.3285173774E-03 -3.4486994026E-04 + -2.0539372625E-03 -1.2482390826E-03 2.3859847721E-03 + 8.2716975819E-03 -2.4692778169E-03 -1.9227275978E-03 + -4.7383116385E-03 4.3471999164E-04 1.1154981197E-02 + 2.1931331490E-03 -2.9147932007E-03 -1.4117258338E-02 + -1.6204634343E-02 1.0152803556E-02 1.1493350422E-03 + 2.0630652073E-02 -2.7451561875E-03 1.2522911218E-03 + -6.0669969477E-04 -1.7931033504E-04 1.5088122881E-02 + 4.4958937188E-03 -1.3990933451E-03 -1.6679941971E-02 + -2.1415768107E-02 3.5842773976E-03 6.4222626642E-03 + 2.9881690773E-03 3.5340815073E-03 -1.1908192559E-02 + -1.0668307547E-02 -8.8902567419E-04 1.0000296462E-02 + 1.3723795281E-02 2.2889216453E-03 -4.2535918764E-03 + -1.8167037144E-03 -2.4014408107E-03 1.0183586380E-02 + 1.0199410740E-02 4.0532717697E-03 -1.3652009583E-02 + -2.4331779848E-02 2.1329964819E-03 -1.5473348205E-03 + 1.8315077309E-02 5.6077339053E-04 -8.7904337928E-03 + -4.6156592755E-03 -6.1209874038E-04 1.1485652602E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5437678830E+03 +:LATVEC_SCALE: + 1.5245970998E+01 1.5245970998E+01 1.5245970998E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0746964484E+00 2.7631951145E-03 1.1915065492E-03 + 2.7631951145E-03 7.9792706677E-01 1.7561672089E-01 + 1.1915065492E-03 1.7561672089E-01 9.0439482923E-01 +:STRESS: + -2.9968762220E+00 -3.2783217399E-01 1.2730123671E+00 + -3.2783217399E-01 1.3900200895E+00 4.0924262689E-02 + 1.2730123671E+00 4.0924262689E-02 -2.1241728250E+00 +:CONSTRESS: + 3.8372062650E+00 6.5033206950E-01 -2.5012128748E+00 + 6.5033206950E-01 -5.6519348935E+00 2.6858567932E-01 + -2.5012128748E+00 2.6858567932E-01 1.8147286286E+00 +:TOTSTRESS: + 2.3436640540E-01 -3.1973670039E-01 1.2293920143E+00 + -3.1973670039E-01 5.0598418708E+00 -1.3389322111E-01 + 1.2293920143E+00 -1.3389322111E-01 1.2138390256E+00 +:PRESIO: 9.2567278148E-01 +:PRES: 1.2436763191E+00 +:CONPRES: -2.3259198328E-14 +:TOTPRES: 2.1693491006E+00 +:PRESIG: 9.5553319378E-01 +:MIND: +Al - Al: 4.7040492642E+00 +Si - Si: 4.7546465655E+00 +Al - Si: 4.8681656138E+00 + + +:MDSTEP: 24 +:MDTM: 13.68 +:TWIST: 0 +:TEL: 1120 +:TIO: 1137.44536378379 +:TEN: -3.2407156621E+00 +:KEN: 5.2342654245E-03 +:KENIG: 5.4031126962E-03 +:FEN: -3.2459499275E+00 +:UEN: -3.2450812372E+00 +:TSEN: -8.6869024611E-04 +:NPH_HAMIL: -8.8359718518E-05 +:NPH_ENTHALPY: -1.0368221486E+02 +:R: + 3.7332195982E-01 3.1662176239E-01 1.8258928083E-01 + 3.8531997924E+00 1.5239020105E+01 4.0266968018E+00 + 7.8872932828E+00 1.5113116823E+01 1.5485403119E-01 + 1.1321595990E+01 1.5243719666E+01 3.6419004270E+00 + 1.2006667404E-01 7.8232169519E+00 1.5247586359E+01 + 3.7349512121E+00 7.8155250817E+00 3.7896865764E+00 + 7.3077205998E+00 7.4182871057E+00 1.1930504425E-01 + 1.1459101784E+01 7.7128686169E+00 3.9727912871E+00 + 5.4554467416E-01 1.5102573891E+01 7.6858897874E+00 + 3.6489905781E+00 2.6321097170E-02 1.1205572271E+01 + 7.6428258045E+00 3.9815997879E-02 7.7958608251E+00 + 1.1496615497E+01 1.5105834919E+01 1.1636527798E+01 + 2.3240196004E-01 7.6469958091E+00 7.7909770491E+00 + 4.1294961116E+00 7.7988064221E+00 1.1420661412E+01 + 7.3413473183E+00 7.8949353569E+00 7.5150882536E+00 + 1.1462176653E+01 7.3041052791E+00 1.1423823212E+01 + 6.8836865749E-02 3.8910915588E+00 3.8947496237E+00 + 3.7236541197E+00 3.8384866487E+00 1.5264696078E+01 + 7.7600835939E+00 3.6526845564E+00 3.4889372768E+00 + 1.1342202376E+01 3.7868522711E+00 1.5137474473E+01 + 3.1297262154E-01 1.1375688627E+01 3.8795080476E+00 + 3.6392893982E+00 1.1485995268E+01 4.8406583987E-01 + 7.7563998149E+00 1.1591844135E+01 3.8357882571E+00 + 1.1087524306E+01 1.1436371705E+01 5.3051329681E-02 + 1.1087210628E-01 3.7075992768E+00 1.1234499830E+01 + 3.8062433804E+00 3.7022433019E+00 7.8547239482E+00 + 7.8192386648E+00 3.7579727001E+00 1.1468600217E+01 + 1.1327542092E+01 3.9185918088E+00 7.7444019060E+00 + 2.9321133076E-01 1.1452878328E+01 1.1452747406E+01 + 3.7115547868E+00 1.1229580284E+01 7.8594489054E+00 + 7.7587226665E+00 1.1631578934E+01 1.1610128007E+01 + 1.1542121139E+01 1.1461269484E+01 7.7442987022E+00 +:V: + -8.6500165363E-05 5.2427520040E-04 3.0946835242E-04 + 1.1637055788E-04 -3.7584922045E-05 3.3935425997E-04 + 3.8451686799E-04 -2.4782906489E-04 -2.9145725379E-04 + -1.8258965421E-04 -3.9804590348E-05 -2.6174813946E-04 + 2.0361705069E-04 2.9643074554E-04 -3.3231809712E-05 + -1.5319918566E-04 3.1414920296E-04 -3.8077992415E-05 + -5.1257166529E-04 -3.5167686531E-04 2.1537084272E-04 + 1.2988053522E-05 1.3445107442E-04 2.5662613279E-04 + 1.3429325034E-04 -2.7380639353E-04 6.2191256240E-05 + -2.2923305785E-04 4.3660475024E-05 -3.5946244029E-04 + 2.7193879135E-05 6.4369475065E-05 -2.4696239392E-04 + 1.0638781507E-04 -2.6527930721E-04 3.2457986257E-04 + 3.9773354581E-04 3.4864248702E-05 2.7445854218E-04 + 5.0399782539E-04 2.5816760881E-04 -5.0836594931E-05 + -4.7058395970E-04 4.2565545905E-04 -1.9404372098E-04 + 7.0223426537E-06 -5.7427538603E-04 -3.3283420394E-05 + 1.4479623985E-04 1.1333028175E-04 1.2961293850E-04 + -1.7740050235E-04 3.9978456309E-05 6.0004090298E-05 + 2.4091362243E-04 -2.8698506114E-04 -6.3387481991E-04 + -2.5608655815E-04 -8.8965262215E-06 -2.1920615251E-04 + 1.1565882959E-04 -1.3566519915E-04 9.6849769668E-05 + -3.1868101441E-04 5.7367079159E-05 3.5364836160E-05 + 2.5194127531E-04 2.3849173901E-04 -6.4785621215E-05 + -7.3858476279E-04 1.6045464515E-06 1.4327347813E-04 + 2.0760156836E-04 -1.7113309496E-04 -4.2041701722E-04 + -6.6659674057E-05 -1.9776203096E-04 4.4679390186E-04 + 3.8611291593E-04 -8.7021505763E-05 7.8044844049E-06 + -2.1822580123E-04 1.6741534999E-04 2.2466278481E-04 + 3.8112535260E-05 1.9773696509E-05 -7.3022726622E-05 + -2.9354057805E-04 -3.7690437893E-04 -4.7399450870E-04 + 3.1443326474E-04 3.1136292941E-04 2.1352787525E-04 + 1.2035869135E-04 2.1290361918E-05 2.6518525012E-04 +:F: + -2.4173633774E-03 -4.8791581408E-03 -1.2023329467E-03 + 1.0612830272E-02 5.3737022695E-04 -5.4381108325E-03 + -1.4434528927E-02 3.4860063417E-03 -6.4090317792E-03 + 8.3343267945E-03 -1.2172240104E-03 8.3248618064E-03 + -1.5674421849E-03 -6.2170968836E-03 -3.8713766026E-04 + -3.3070986781E-03 1.2140331606E-03 1.1953615844E-03 + 1.0084160740E-02 4.1977243976E-03 5.3791032562E-04 + 6.7134127338E-05 8.2080141499E-04 -1.3401633916E-03 + -2.1621794904E-02 2.3922283631E-04 -7.9818499940E-03 + 1.2969101690E-02 -2.5511172759E-03 1.4883245430E-02 + 1.5123980365E-03 -7.7654655563E-05 1.7535092301E-03 + 6.2079352856E-03 5.7783481949E-04 -1.2428376854E-03 + -2.7054356318E-03 2.4331694285E-03 5.1873798577E-04 + -6.2491739560E-03 -5.3104774757E-03 1.3099736484E-03 + 8.5396658440E-03 -5.5396324948E-03 -6.1676990198E-04 + -1.8637131663E-03 -1.0931671139E-03 2.4398203883E-03 + 8.7227121969E-03 -2.3288377352E-03 -2.1214639018E-03 + -4.9672670278E-03 5.1958385822E-04 1.1121415725E-02 + 1.9341579341E-03 -3.1989537126E-03 -1.4021996669E-02 + -1.6543424537E-02 1.0415348822E-02 1.2120188787E-03 + 2.0665067474E-02 -2.8747440908E-03 1.4802997507E-03 + -3.6894639018E-04 -5.4466921144E-05 1.5197981229E-02 + 4.0413461857E-03 -1.4821750534E-03 -1.6480478788E-02 + -2.0909840111E-02 3.2597305924E-03 6.1372582617E-03 + 2.7432215883E-03 3.6103878051E-03 -1.1994306600E-02 + -1.0691600706E-02 -8.6551420854E-04 9.4750438300E-03 + 1.3848459827E-02 2.1549993111E-03 -4.1904721005E-03 + -1.8823694044E-03 -2.6031118123E-03 1.0556128559E-02 + 1.0071332917E-02 4.3377641175E-03 -1.3506170675E-02 + -2.4661840951E-02 2.5840985833E-03 -1.8153736343E-03 + 1.8102637039E-02 6.5899592049E-04 -8.6116387045E-03 + -4.2646479984E-03 -7.5374005198E-04 1.1216568632E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5574307375E+03 +:LATVEC_SCALE: + 1.5265539280E+01 1.5265539280E+01 1.5265539280E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0765542813E+00 5.3649465552E-03 -4.2076252091E-03 + 5.3649465552E-03 7.8846930413E-01 1.7490515816E-01 + -4.2076252091E-03 1.7490515816E-01 9.0546856489E-01 +:STRESS: + -2.7546669434E+00 -3.3470404990E-01 1.3010433639E+00 + -3.3470404990E-01 1.4406247300E+00 3.9595193307E-02 + 1.3010433639E+00 3.9595193307E-02 -1.8221820471E+00 +:CONSTRESS: + 3.7531578392E+00 6.6853188951E-01 -2.5689925900E+00 + 6.6853188951E-01 -5.3655507190E+00 2.7003038766E-01 + -2.5689925900E+00 2.7003038766E-01 1.6123928798E+00 +:TOTSTRESS: + 7.8063385485E-02 -3.2846289305E-01 1.2637416009E+00 + -3.2846289305E-01 4.7133952931E+00 -1.3472042281E-01 + 1.2637416009E+00 -1.3472042281E-01 1.1152577322E+00 +:PRESIO: 9.2349738344E-01 +:PRES: 1.0454080868E+00 +:CONPRES: 3.4423613525E-14 +:TOTPRES: 1.9689054703E+00 +:PRESIG: 9.5328762162E-01 +:MIND: +Al - Al: 4.6963145801E+00 +Si - Si: 4.7545324313E+00 +Al - Si: 4.8643504536E+00 + + +:MDSTEP: 25 +:MDTM: 13.76 +:TWIST: 0 +:TEL: 1120 +:TIO: 1139.20889071406 +:TEN: -3.2407438100E+00 +:KEN: 5.2423807752E-03 +:KENIG: 5.4114898325E-03 +:FEN: -3.2459861908E+00 +:UEN: -3.2451358526E+00 +:TSEN: -8.5033819649E-04 +:NPH_HAMIL: -1.0150524525E-04 +:NPH_ENTHALPY: -1.0368222800E+02 +:R: + 3.7164649932E-01 3.3002673381E-01 1.9050682461E-01 + 3.8611945177E+00 1.5258014481E+01 4.0403561447E+00 + 7.9070655991E+00 1.5126743164E+01 1.4777735964E-01 + 1.1331915776E+01 1.5262654067E+01 3.6402131251E+00 + 1.2527112907E-01 7.8407691388E+00 1.5266694264E+01 + 3.7360087780E+00 7.8335538307E+00 3.7937032005E+00 + 7.3046074875E+00 7.4192778739E+00 1.2481362125E-01 + 1.1474407190E+01 7.7262974749E+00 3.9843510762E+00 + 5.4945801414E-01 1.5115520908E+01 7.6974335049E+00 + 3.6481492186E+00 2.7423939843E-02 1.1211388341E+01 + 7.6535034409E+00 4.1466330731E-02 7.7999307705E+00 + 1.1514328204E+01 1.5119000110E+01 1.1659796064E+01 + 2.4256748348E-01 7.6578751754E+00 7.8079835407E+00 + 4.1473740759E+00 7.8153820199E+00 1.1434339113E+01 + 7.3393113581E+00 7.9157951434E+00 7.5200906076E+00 + 1.1477325815E+01 7.2993848851E+00 1.1437948096E+01 + 7.2575692867E-02 3.8989798335E+00 3.9030483455E+00 + 3.7240866455E+00 3.8445014250E+00 7.1294866412E-04 + 7.7762249185E+00 3.6503131519E+00 3.4776708670E+00 + 1.1350571904E+01 3.7916451589E+00 1.5151829036E+01 + 3.1637881118E-01 1.1387175117E+01 3.8869947659E+00 + 3.6361302675E+00 1.1502437342E+01 4.8566855072E-01 + 7.7728228985E+00 1.1612914652E+01 3.8390951649E+00 + 1.1083550648E+01 1.1451383851E+01 5.6716140005E-02 + 1.1618982688E-01 3.7082180878E+00 1.1238674394E+01 + 3.8094999442E+00 3.7021667892E+00 7.8761478860E+00 + 7.8391353722E+00 3.7607377167E+00 1.1483763662E+01 + 1.1336921024E+01 3.9278577136E+00 7.7601709789E+00 + 2.9460190423E-01 1.1468369813E+01 1.1465826546E+01 + 3.7089683914E+00 1.1234916868E+01 7.8579412302E+00 + 7.7767855225E+00 1.1654524206E+01 1.1630559497E+01 + 1.1560175802E+01 1.1476778975E+01 7.7610780808E+00 +:V: + -8.7534195818E-05 5.2109069363E-04 3.0844639962E-04 + 1.2158771556E-04 -3.7292137747E-05 3.3613010906E-04 + 3.7655417470E-04 -2.4567178564E-04 -2.9432212293E-04 + -1.7807888993E-04 -4.0375433750E-05 -2.5714245579E-04 + 2.0253951170E-04 2.9290189901E-04 -3.3380865276E-05 + -1.5468585887E-04 3.1436794046E-04 -3.7463808107E-05 + -5.0678672940E-04 -3.4907399768E-04 2.1530421802E-04 + 1.3041223729E-05 1.3472543618E-04 2.5566672819E-04 + 1.2311170585E-04 -2.7336739522E-04 5.8005811613E-05 + -2.2230288558E-04 4.2231728536E-05 -3.5132884304E-04 + 2.7914220696E-05 6.4295349836E-05 -2.4568118113E-04 + 1.0945678033E-04 -2.6466928857E-04 3.2345860721E-04 + 3.9574361032E-04 3.6043707696E-05 2.7435242696E-04 + 5.0021387420E-04 2.5514672688E-04 -5.0033009675E-05 + -4.6554876725E-04 4.2225521589E-04 -1.9417030043E-04 + 6.1246048015E-06 -5.7403441069E-04 -3.1997859628E-05 + 1.4893486287E-04 1.1209083216E-04 1.2836771132E-04 + -1.7963113917E-04 4.0200173989E-05 6.5299101225E-05 + 2.4148017578E-04 -2.8822633220E-04 -6.3980899922E-04 + -2.6384106003E-04 -3.7848815519E-06 -2.1831773120E-04 + 1.2551065309E-04 -1.3690872282E-04 9.7487899491E-05 + -3.1839025576E-04 5.7295717871E-05 4.2699922069E-05 + 2.5346113825E-04 2.3744158868E-04 -7.2629229841E-05 + -7.4760783375E-04 3.0950199945E-06 1.4599566153E-04 + 2.0859633387E-04 -1.6914488800E-04 -4.2568691143E-04 + -7.1748549081E-05 -1.9791300737E-04 4.5066649932E-04 + 3.9233779153E-04 -8.5901653374E-05 5.7813442602E-06 + -2.1887036372E-04 1.6588760819E-04 2.2955648423E-04 + 4.2909754808E-05 2.1916986608E-05 -7.9429337153E-05 + -3.0516891264E-04 -3.7505006306E-04 -4.7430939430E-04 + 3.2272541855E-04 3.1129609605E-04 2.0911652954E-04 + 1.1822035277E-04 2.0862277866E-05 2.7020451874E-04 +:F: + -2.1343756963E-03 -5.0412006690E-03 -1.2494947194E-03 + 1.0693345015E-02 4.2980373456E-04 -5.5977638282E-03 + -1.5170901220E-02 3.7903599763E-03 -6.4698111425E-03 + 8.6194297476E-03 -1.2542818078E-03 8.5954015861E-03 + -1.6534264778E-03 -6.2503977458E-03 -3.7656158128E-04 + -3.3862357975E-03 1.2817476252E-03 1.0446966734E-03 + 1.0216139254E-02 4.3088933004E-03 3.1382447930E-04 + 2.1106654567E-04 9.6453156472E-04 -1.1374272238E-03 + -2.2053765063E-02 8.4187281749E-05 -8.3047781369E-03 + 1.3343838983E-02 -2.8921189072E-03 1.5530264107E-02 + 1.4870575899E-03 1.1691625105E-04 2.0508595431E-03 + 6.5216926616E-03 4.6838953210E-04 -1.5245963892E-03 + -3.1300304985E-03 2.4279330396E-03 4.8233549400E-04 + -6.1551964469E-03 -5.3395309453E-03 1.6152756107E-03 + 9.0027777111E-03 -5.7478149045E-03 -8.9082160022E-04 + -1.6625224272E-03 -9.2637062095E-04 2.4891729046E-03 + 9.1529253422E-03 -2.1796634550E-03 -2.3228517056E-03 + -5.2032430514E-03 6.1180665784E-04 1.1073766121E-02 + 1.7055720412E-03 -3.4759166696E-03 -1.3908574971E-02 + -1.6868242939E-02 1.0650618066E-02 1.2753422939E-03 + 2.0652589431E-02 -2.9933819667E-03 1.6777882125E-03 + -1.4901711087E-04 6.9034706674E-05 1.5290927320E-02 + 3.5957341990E-03 -1.5691888399E-03 -1.6267810586E-02 + -2.0344728347E-02 2.9056889113E-03 5.8798850868E-03 + 2.4856253878E-03 3.6790174594E-03 -1.2040974648E-02 + -1.0687986901E-02 -8.2477478840E-04 8.9312294706E-03 + 1.3946402582E-02 2.0013957884E-03 -4.1242381659E-03 + -1.9570181194E-03 -2.8042663225E-03 1.0869260741E-02 + 9.9496522144E-03 4.6217519575E-03 -1.3350859641E-02 + -2.4953070597E-02 3.0421639580E-03 -2.0416582374E-03 + 1.7844926591E-02 7.4424109986E-04 -8.4582438006E-03 + -3.9190146027E-03 -8.9957326785E-04 1.0946436732E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5714026599E+03 +:LATVEC_SCALE: + 1.5285498470E+01 1.5285498470E+01 1.5285498470E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0784949216E+00 7.9888291211E-03 -9.3779043551E-03 + 7.9888291211E-03 7.7892453229E-01 1.7419399226E-01 + -9.3779043551E-03 1.7419399226E-01 9.0651271301E-01 +:STRESS: + -2.5161520545E+00 -3.4227527486E-01 1.3277961513E+00 + -3.4227527486E-01 1.4982557487E+00 3.8505636898E-02 + 1.3277961513E+00 3.8505636898E-02 -1.5226279144E+00 +:CONSTRESS: + 3.6774921732E+00 6.8811625419E-01 -2.6340099352E+00 + 6.8811625419E-01 -5.0922268479E+00 2.7102610986E-01 + -2.6340099352E+00 2.7102610986E-01 1.4147346748E+00 +:TOTSTRESS: + -8.2845197003E-02 -3.3785215021E-01 1.2968358795E+00 + -3.3785215021E-01 4.3728956316E+00 -1.3533775449E-01 + 1.2968358795E+00 -1.3533775449E-01 1.0144059526E+00 +:PRESIO: 9.2131072230E-01 +:PRES: 8.4684140675E-01 +:CONPRES: 1.1496689459E-14 +:TOTPRES: 1.7681521291E+00 +:PRESIG: 9.5103042302E-01 +:MIND: +Al - Al: 4.6892145527E+00 +Si - Si: 4.7542670449E+00 +Al - Si: 4.8586639617E+00 + + +:MDSTEP: 26 +:MDTM: 25.83 +:TWIST: 0 +:TEL: 1120 +:TIO: 1141.03849771864 +:TEN: -3.2407692477E+00 +:KEN: 5.2508002114E-03 +:KENIG: 5.4201808634E-03 +:FEN: -3.2460200479E+00 +:UEN: -3.2451869540E+00 +:TSEN: -8.3309384799E-04 +:NPH_HAMIL: -1.0721077918E-04 +:NPH_ENTHALPY: -1.0368223371E+02 +:R: + 3.6995259741E-01 3.4337623162E-01 1.9841315031E-01 + 3.8694098906E+00 1.5277356586E+01 4.0540362008E+00 + 7.9268254972E+00 1.5140756276E+01 1.4062281083E-01 + 1.1342597708E+01 1.5281915204E+01 3.6387150384E+00 + 1.3045778806E-01 7.8584191164E+00 1.5286139994E+01 + 3.7371076777E+00 7.8517745685E+00 3.7978180156E+00 + 7.3017859865E+00 7.4204889125E+00 1.3032904058E-01 + 1.1489972713E+01 7.7399118491E+00 3.9959861513E+00 + 5.5310749769E-01 1.5128808005E+01 7.7090459426E+00 + 3.6475567499E+00 2.8491192478E-02 1.1217650329E+01 + 7.6643714504E+00 4.3119091589E-02 7.8042012961E+00 + 1.1532381022E+01 1.5132510276E+01 1.1683307025E+01 + 2.5269944601E-01 7.6689568026E+00 7.8251714131E+00 + 4.1652682565E+00 7.8320662290E+00 1.1448293589E+01 + 7.3375526102E+00 7.9367607661E+00 7.5252504412E+00 + 1.1492711686E+01 7.2948163779E+00 1.1452360792E+01 + 7.6426371279E-02 3.9069294223E+00 3.9114067579E+00 + 3.7245400253E+00 3.8506098485E+00 2.4024111371E-03 + 7.7925613773E+00 3.6479816769E+00 3.4663147857E+00 + 1.1358992991E+01 3.7966512922E+00 1.5166538815E+01 + 3.2004069745E-01 1.1398881023E+01 3.8945889424E+00 + 3.6330507684E+00 1.1519138371E+01 4.8746619201E-01 + 7.7894637924E+00 1.1634226981E+01 3.8422924114E+00 + 1.1079580472E+01 1.1466687914E+01 6.0453056508E-02 + 1.2154017385E-01 3.7089642912E+00 1.1242956016E+01 + 3.8127133307E+00 3.7021633198E+00 7.8978562613E+00 + 7.8593760091E+00 3.7636111585E+00 1.1499135155E+01 + 1.1346530674E+01 3.9371780916E+00 7.7762450955E+00 + 2.9611884418E-01 1.1484174259E+01 1.1479002255E+01 + 3.7061647770E+00 1.1240541962E+01 7.8565850607E+00 + 7.7952377880E+00 1.1677740102E+01 1.1651150279E+01 + 1.1578442754E+01 1.1492535171E+01 7.7781634730E+00 +:V: + -8.8425146090E-05 5.1782264537E-04 3.0739683025E-04 + 1.2683109147E-04 -3.7052742953E-05 3.3282611555E-04 + 3.6822363995E-04 -2.4335168010E-04 -2.9720599079E-04 + -1.7342879304E-04 -4.0961117082E-05 -2.5240212567E-04 + 2.0141964569E-04 2.8935827799E-04 -3.3524654799E-05 + -1.5620389068E-04 3.1461001316E-04 -3.6929299589E-05 + -5.0093871311E-04 -3.4641489396E-04 2.1511839628E-04 + 1.3167718150E-05 1.3506753135E-04 2.5481004481E-04 + 1.1173094211E-04 -2.7300358483E-04 5.3666452157E-05 + -2.1519217892E-04 4.0631378904E-05 -3.4287530917E-04 + 2.8621141663E-05 6.4319674323E-05 -2.4424857019E-04 + 1.1267903776E-04 -2.6410919002E-04 3.2218994337E-04 + 3.9353219571E-04 3.7213402348E-05 2.7422215966E-04 + 4.9647737422E-04 2.5211466935E-04 -4.9073843165E-05 + -4.6028025267E-04 4.1874688314E-04 -1.9443139959E-04 + 5.3319962745E-06 -5.7369469636E-04 -3.0689280379E-05 + 1.5326769664E-04 1.1092446399E-04 1.2702335262E-04 + -1.8197114708E-04 4.0466779980E-05 7.0559148965E-05 + 2.4193857811E-04 -2.8959196549E-04 -6.4566377398E-04 + -2.7173372571E-04 1.4273809641E-06 -2.1739408851E-04 + 1.3532976528E-04 -1.3820224638E-04 9.8212092610E-05 + -3.1799094683E-04 5.7282829405E-05 5.0065231197E-05 + 2.5476075236E-04 2.3634493985E-04 -8.0354866421E-05 + -7.5631711339E-04 4.4053519185E-06 1.4859309534E-04 + 2.0945857122E-04 -1.6712437592E-04 -4.3095481741E-04 + -7.6821814337E-05 -1.9803576069E-04 4.5425780919E-04 + 3.9858695354E-04 -8.4860492578E-05 3.7937674148E-06 + -2.1954744578E-04 1.6426149956E-04 2.3457585736E-04 + 4.7643165619E-05 2.4193815718E-05 -8.5748750659E-05 + -3.1690745404E-04 -3.7296732767E-04 -4.7471323555E-04 + 3.3086461310E-04 3.1126080812E-04 2.0477507197E-04 + 1.1624847496E-04 2.0362790037E-05 2.7508065112E-04 +:F: + -1.8621559015E-03 -5.1845373824E-03 -1.2919398117E-03 + 1.0754115944E-02 3.2396977672E-04 -5.7442012323E-03 + -1.5904912291E-02 4.1232301412E-03 -6.5235568706E-03 + 8.8961856255E-03 -1.2824157944E-03 8.8621256922E-03 + -1.7244173807E-03 -6.2701171239E-03 -3.6975703751E-04 + -3.4520132297E-03 1.3335985822E-03 8.7932407511E-04 + 1.0323103617E-02 4.4058297903E-03 8.2232995317E-05 + 3.5945347785E-04 1.1020877399E-03 -9.1656397636E-04 + -2.2460666369E-02 -7.9293185153E-05 -8.6097415542E-03 + 1.3703471475E-02 -3.2360857261E-03 1.6166496363E-02 + 1.4651925531E-03 3.1791277692E-04 2.3408299773E-03 + 6.8412587114E-03 3.6118983287E-04 -1.8070995065E-03 + -3.5622307334E-03 2.4035532995E-03 4.4486693511E-04 + -6.0395790815E-03 -5.3496665963E-03 1.9274540277E-03 + 9.4536438569E-03 -5.9516585111E-03 -1.1671887850E-03 + -1.4507192237E-03 -7.4721982106E-04 2.5352541031E-03 + 9.5601632667E-03 -2.0241295076E-03 -2.5267347173E-03 + -5.4465097174E-03 7.0963722057E-04 1.1011371808E-02 + 1.5111231409E-03 -3.7440319057E-03 -1.3780956163E-02 + -1.7178838742E-02 1.0858444803E-02 1.3436730961E-03 + 2.0594263552E-02 -3.0997429355E-03 1.8476125330E-03 + 5.3813999112E-05 1.9157086965E-04 1.5366357793E-02 + 3.1615003396E-03 -1.6596565639E-03 -1.6042037808E-02 + -1.9726669411E-02 2.5240210136E-03 5.6492243649E-03 + 2.2190402940E-03 3.7401854482E-03 -1.2051146779E-02 + -1.0660934527E-02 -7.6668198404E-04 8.3727315318E-03 + 1.4016166357E-02 1.8287139812E-03 -4.0540807725E-03 + -2.0388995639E-03 -3.0035561521E-03 1.1121499685E-02 + 9.8375037098E-03 4.9028882170E-03 -1.3187615185E-02 + -2.5206382506E-02 3.5056348956E-03 -2.2250904338E-03 + 1.7543509915E-02 8.1554777092E-04 -8.3290517141E-03 + -3.5785811545E-03 -1.0492229703E-03 1.0675707365E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5856521602E+03 +:LATVEC_SCALE: + 1.5305800640E+01 1.5305800640E+01 1.5305800640E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0805366893E+00 1.0624790285E-02 -1.4306701702E-02 + 1.0624790285E-02 7.6931387301E-01 1.7347176584E-01 + -1.4306701702E-02 1.7347176584E-01 9.0751897219E-01 +:STRESS: + -2.2823437764E+00 -3.5061108408E-01 1.3530702082E+00 + -3.5061108408E-01 1.5620641058E+00 3.7697794373E-02 + 1.3530702082E+00 3.7697794373E-02 -1.2276383718E+00 +:CONSTRESS: + 3.6097022679E+00 7.0919822462E-01 -2.6958220812E+00 + 7.0919822462E-01 -4.8330085051E+00 2.7149116977E-01 + -2.6958220812E+00 2.7149116977E-01 1.2233062372E+00 +:TOTSTRESS: + -2.4682180219E-01 -3.4796235026E-01 1.3284451713E+00 + -3.4796235026E-01 4.0402582723E+00 -1.3571719830E-01 + 1.3284451713E+00 -1.3571719830E-01 9.1185110686E-01 +:PRESIO: 9.1912317818E-01 +:PRES: 6.4930601415E-01 +:CONPRES: 0.0000000000E+00 +:TOTPRES: 1.5684291923E+00 +:PRESIG: 9.4877231296E-01 +:MIND: +Al - Al: 4.6827496749E+00 +Si - Si: 4.7538387642E+00 +Al - Si: 4.8420108891E+00 + + +:MDSTEP: 27 +:MDTM: 13.60 +:TWIST: 0 +:TEL: 1120 +:TIO: 1142.93576686138 +:TEN: -3.2407917908E+00 +:KEN: 5.2595310134E-03 +:KENIG: 5.4291933042E-03 +:FEN: -3.2460513218E+00 +:UEN: -3.2452342657E+00 +:TSEN: -8.1705609311E-04 +:NPH_HAMIL: -1.0410788946E-04 +:NPH_ENTHALPY: -1.0368223060E+02 +:R: + 3.6824247898E-01 3.5666764603E-01 2.0630726021E-01 + 3.8778347920E+00 1.5296997915E+01 4.0677227782E+00 + 7.9465394834E+00 1.5155113475E+01 1.3338913303E-01 + 1.1353610157E+01 1.5301455530E+01 3.6373981578E+00 + 1.3562545472E-01 7.8761425152E+00 1.5305876430E+01 + 3.7382354748E+00 7.8701638571E+00 3.8020172092E+00 + 7.2992346604E+00 7.4218983648E+00 1.3584810186E-01 + 1.1505764749E+01 7.7536896345E+00 4.0076870648E+00 + 5.5648636585E-01 1.5142386302E+01 7.7206995057E+00 + 3.6472063191E+00 2.9518476852E-02 1.1224331418E+01 + 7.6754059137E+00 4.4776695890E-02 7.8086518269E+00 + 1.1550742409E+01 1.5146317236E+01 1.1707021230E+01 + 2.6279184062E-01 7.6802167302E+00 7.8425161722E+00 + 4.1831674788E+00 7.8488348638E+00 1.1462493387E+01 + 7.3360538548E+00 7.9578053692E+00 7.5305409692E+00 + 1.1508301445E+01 7.2903792082E+00 1.1467026510E+01 + 8.0393642256E-02 3.9149301886E+00 3.9198103929E+00 + 3.7249997453E+00 3.8568012294E+00 4.2244640562E-03 + 7.8090666913E+00 3.6456755040E+00 3.4548595546E+00 + 1.1367426700E+01 3.8018614564E+00 1.5181557711E+01 + 3.2395666231E-01 1.1410769810E+01 3.9022806458E+00 + 3.6300419746E+00 1.1536064298E+01 4.8945819588E-01 + 7.8062933481E+00 1.1655744231E+01 3.8453708086E+00 + 1.1075586647E+01 1.1482243909E+01 6.4259189803E-02 + 1.2691966482E-01 3.7098270950E+00 1.1247309655E+01 + 3.8158720553E+00 3.7022220693E+00 7.9198181928E+00 + 7.8799373488E+00 3.7665792894E+00 1.1514680044E+01 + 1.1356334925E+01 3.9465384682E+00 7.7926034021E+00 + 2.9775991306E-01 1.1500259610E+01 1.1492241016E+01 + 3.7031292943E+00 1.1246426265E+01 7.8553537088E+00 + 7.8140519364E+00 1.1701191580E+01 1.1671866035E+01 + 1.1596890406E+01 1.1508500803E+01 7.7955277453E+00 +:V: + -8.9178878892E-05 5.1448272135E-04 3.0632291977E-04 + 1.3209096054E-04 -3.6865680126E-05 3.2944985909E-04 + 3.5952810189E-04 -2.4085538439E-04 -3.0010598363E-04 + -1.6864498524E-04 -4.1557231043E-05 -2.4753018685E-04 + 2.0026547238E-04 2.8580757327E-04 -3.3665558738E-05 + -1.5774640403E-04 3.1486796426E-04 -3.6481341602E-05 + -4.9504156253E-04 -3.4370788174E-04 2.1481074837E-04 + 1.3369415739E-05 1.3547438468E-04 2.5406557010E-04 + 1.0016492511E-04 -2.7271969501E-04 4.9182913514E-05 + -2.0790983560E-04 3.8858520495E-05 -3.3410925794E-04 + 2.9316911386E-05 6.4445279389E-05 -2.4266959672E-04 + 1.1605725942E-04 -2.6359870185E-04 3.2077481736E-04 + 3.9109739717E-04 3.8363319596E-05 2.7406833171E-04 + 4.9280010143E-04 2.4908210294E-04 -4.7956779734E-05 + -4.5478701852E-04 4.1513453699E-04 -1.9482865704E-04 + 4.6496602263E-06 -5.7325159183E-04 -2.9359158381E-05 + 1.5778375141E-04 1.0983409600E-04 1.2557932983E-04 + -1.8442417881E-04 4.0780377777E-05 7.5777325341E-05 + 2.4230691131E-04 -2.9107767640E-04 -6.5143496671E-04 + -2.7975795753E-04 6.7269393406E-06 -2.1643251752E-04 + 1.4509410743E-04 -1.3953996350E-04 9.9009817566E-05 + -3.1749215203E-04 5.7328240152E-05 5.7452137014E-05 + 2.5584697176E-04 2.3520084637E-04 -8.7956335919E-05 + -7.6469075918E-04 5.5223901241E-06 1.5107863004E-04 + 2.1018527807E-04 -1.6507551646E-04 -4.3620501667E-04 + -8.1869041519E-05 -1.9812196176E-04 4.5756297505E-04 + 4.0484748892E-04 -8.3907255191E-05 1.8438587907E-06 + -2.2026098211E-04 1.6253872745E-04 2.3969168798E-04 + 5.2318102234E-05 2.6601907132E-05 -9.1977539152E-05 + -3.2873833479E-04 -3.7065571501E-04 -4.7518641787E-04 + 3.3883094481E-04 3.1125077143E-04 2.0049270938E-04 + 1.1444072549E-04 1.9790371956E-05 2.7981424998E-04 +:F: + -1.6007107607E-03 -5.3077471526E-03 -1.3302752931E-03 + 1.0795411104E-02 2.2082168500E-04 -5.8788970874E-03 + -1.6637896849E-02 4.4848956228E-03 -6.5697548714E-03 + 9.1626268081E-03 -1.3016320529E-03 9.1252379158E-03 + -1.7815054643E-03 -6.2771696774E-03 -3.6820034982E-04 + -3.5023039349E-03 1.3679322383E-03 7.0150551383E-04 + 1.0407285392E-02 4.4890188103E-03 -1.5564550138E-04 + 5.1108332113E-04 1.2327253526E-03 -6.7897312178E-04 + -2.2841464267E-02 -2.5001926814E-04 -8.8962048431E-03 + 1.4047675605E-02 -3.5823475004E-03 1.6791398161E-02 + 1.4485380336E-03 5.2343259223E-04 2.6222886738E-03 + 7.1655204448E-03 2.5611698280E-04 -2.0901258809E-03 + -4.0008427690E-03 2.3582488047E-03 4.0721877569E-04 + -5.9054451717E-03 -5.3400958718E-03 2.2435336492E-03 + 9.8904601001E-03 -6.1500484785E-03 -1.4460495389E-03 + -1.2287575276E-03 -5.5418763778E-04 2.5794627212E-03 + 9.9447534508E-03 -1.8641394067E-03 -2.7327471901E-03 + -5.6961786782E-03 8.1031115471E-04 1.0934937340E-02 + 1.3535449398E-03 -4.0004177478E-03 -1.3642362564E-02 + -1.7474906107E-02 1.1040074164E-02 1.4213619298E-03 + 2.0490334513E-02 -3.1930769686E-03 1.9926424842E-03 + 2.4111820734E-04 3.1392397515E-04 1.5424392504E-02 + 2.7398761291E-03 -1.7541031280E-03 -1.5803353520E-02 + -1.9061155558E-02 2.1148242154E-03 5.4427345794E-03 + 1.9457184528E-03 3.7951604584E-03 -1.2028105954E-02 + -1.0613987012E-02 -6.8881579052E-04 7.8019663719E-03 + 1.4056719639E-02 1.6378264463E-03 -3.9793342328E-03 + -2.1272204256E-03 -3.2006285643E-03 1.1312397111E-02 + 9.7376619977E-03 5.1782629356E-03 -1.3017583891E-02 + -2.5422197747E-02 3.9720623042E-03 -2.3647019856E-03 + 1.7199758708E-02 8.7089271524E-04 -8.2232481910E-03 + -3.2435145735E-03 -1.2021012121E-03 1.0404486285E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6001479099E+03 +:LATVEC_SCALE: + 1.5326398543E+01 1.5326398543E+01 1.5326398543E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0826964009E+00 1.3262358064E-02 -1.8984607044E-02 + 1.3262358064E-02 7.5965681782E-01 1.7272705630E-01 + -1.8984607044E-02 1.7272705630E-01 9.0848032918E-01 +:STRESS: + -2.0540353446E+00 -3.5968004343E-01 1.3766317015E+00 + -3.5968004343E-01 1.6311976550E+00 3.7203041247E-02 + 1.3766317015E+00 3.7203041247E-02 -9.3924270473E-01 +:CONSTRESS: + 3.5490524650E+00 7.3179048099E-01 -2.7539752558E+00 + 7.3179048099E-01 -4.5887160162E+00 2.7132963861E-01 + -2.7539752558E+00 2.7132963861E-01 1.0396635513E+00 +:TOTSTRESS: + -4.1232071941E-01 -3.5884807949E-01 1.3583589473E+00 + -3.5884807949E-01 3.7171751791E+00 -1.3580562356E-01 + 1.3583589473E+00 -1.3580562356E-01 8.0805948261E-01 +:PRESIO: 9.1694451597E-01 +:PRES: 4.5402679811E-01 +:CONPRES: -3.4224248968E-14 +:TOTPRES: 1.3709713141E+00 +:PRESIG: 9.4652337133E-01 +:MIND: +Al - Al: 4.6769201163E+00 +Si - Si: 4.7532363581E+00 +Al - Si: 4.8255244223E+00 + + +:MDSTEP: 28 +:MDTM: 13.57 +:TWIST: 0 +:TEL: 1120 +:TIO: 1144.90253896633 +:TEN: -3.2408114107E+00 +:KEN: 5.2685816523E-03 +:KENIG: 5.4385358991E-03 +:FEN: -3.2460799924E+00 +:UEN: -3.2452776652E+00 +:TSEN: -8.0232713047E-04 +:NPH_HAMIL: -9.4508234525E-05 +:NPH_ENTHALPY: -1.0368222100E+02 +:R: + 3.6651827050E-01 3.6989856214E-01 2.1418817403E-01 + 3.8864580849E+00 1.5316890967E+01 4.0814020363E+00 + 7.9661745180E+00 1.5169773428E+01 1.2607522194E-01 + 1.1364922111E+01 1.5321228578E+01 3.6362546977E+00 + 1.4077308446E-01 7.8939155748E+00 1.5325857355E+01 + 3.7393801859E+00 7.8886984866E+00 3.8062870576E+00 + 7.2969323245E+00 7.4234847224E+00 1.4136750153E-01 + 1.1521750456E+01 7.7676091071E+00 4.0194447922E+00 + 5.5958820163E-01 1.5156207823E+01 7.7323673071E+00 + 3.6470911438E+00 3.0501381023E-02 1.1231405410E+01 + 7.6865834553E+00 4.6441608912E-02 7.8132622102E+00 + 1.1569381593E+01 1.5160373826E+01 1.1730899907E+01 + 2.7283853581E-01 7.6916312132E+00 7.8599937730E+00 + 4.2010609869E+00 7.8656644401E+00 1.1476907832E+01 + 7.3347982294E+00 7.9789026009E+00 7.5359358781E+00 + 1.1524063119E+01 7.2860535467E+00 1.1481911163E+01 + 8.4481957603E-02 3.9229722787E+00 3.9282449835E+00 + 3.7254514759E+00 3.8630651487E+00 6.1782084940E-03 + 7.8257154793E+00 3.6433804199E+00 3.4432961422E+00 + 1.1375835021E+01 3.8072663618E+00 1.5196840725E+01 + 3.2812454103E-01 1.1422805838E+01 3.9100598774E+00 + 3.6270950501E+00 1.1553181781E+01 4.9164381018E-01 + 7.8232830213E+00 1.1677430163E+01 3.8483215763E+00 + 1.1071543420E+01 1.1498012238E+01 6.8131923301E-02 + 1.3232471251E-01 3.7107958922E+00 1.1251701444E+01 + 3.8189651233E+00 3.7023327144E+00 7.9420030811E+00 + 7.9007962496E+00 3.7696284041E+00 1.1530364453E+01 + 1.1366298329E+01 3.9559246180E+00 7.8092247629E+00 + 2.9952303402E-01 1.1516594462E+01 1.1505510130E+01 + 3.6998480234E+00 1.1252541280E+01 7.8542215799E+00 + 7.8332003745E+00 1.1724844096E+01 1.1692672868E+01 + 1.1615487812E+01 1.1524639285E+01 7.8131442076E+00 +:V: + -8.9801641325E-05 5.1108337669E-04 3.0522763236E-04 + 1.3735780551E-04 -3.6729660711E-05 3.2600865552E-04 + 3.5047031039E-04 -2.3816941599E-04 -3.0301872103E-04 + -1.6373418834E-04 -4.2159492760E-05 -2.4253022889E-04 + 1.9908503623E-04 2.8225694294E-04 -3.3806435155E-05 + -1.5930589647E-04 3.1513375801E-04 -3.6125892589E-05 + -4.8910847118E-04 -3.4096115714E-04 2.1437877573E-04 + 1.3648015230E-05 1.3594287799E-04 2.5344237782E-04 + 8.8428536888E-05 -2.7251979365E-04 4.4565534332E-05 + -2.0046532838E-04 3.6912836323E-05 -3.2503899226E-04 + 3.0004010987E-05 6.4673908731E-05 -2.4094986778E-04 + 1.1959378632E-04 -2.6313747343E-04 3.1921465429E-04 + 3.8843734693E-04 3.9482749410E-05 2.7389201572E-04 + 4.8919235761E-04 2.4605992179E-04 -4.6680475277E-05 + -4.4907844641E-04 4.1142292748E-04 -1.9536372354E-04 + 4.0823655125E-06 -5.7269999719E-04 -2.8008712310E-05 + 1.6247194026E-04 1.0882157998E-04 1.2403530736E-04 + -1.8699373237E-04 4.1142312223E-05 8.0947040955E-05 + 2.4260432737E-04 -2.9267859554E-04 -6.5712037066E-04 + -2.8790694995E-04 1.2100389008E-05 -2.1542843862E-04 + 1.5478213414E-04 -1.4091546873E-04 9.9869762179E-05 + -3.1690221864E-04 5.7431735427E-05 6.4852133995E-05 + 2.5672746377E-04 2.3400855904E-04 -9.5427516490E-05 + -7.7270971735E-04 6.4338193323E-06 1.5346436800E-04 + 2.1077480781E-04 -1.6300209116E-04 -4.4142352342E-04 + -8.6881505840E-05 -1.9816310484E-04 4.6057867605E-04 + 4.1110633071E-04 -8.3050719357E-05 -6.6232923547E-08 + -2.2101424085E-04 1.6072156621E-04 2.4487484779E-04 + 5.6940961396E-05 2.9137796994E-05 -9.8113221986E-05 + -3.4064409583E-04 -3.6811548137E-04 -4.7570923486E-04 + 3.4660530579E-04 3.1125915693E-04 1.9625908284E-04 + 1.1279497974E-04 1.9143567356E-05 2.8440650885E-04 +:F: + -1.3515572277E-03 -5.4087880027E-03 -1.3649818998E-03 + 1.0817583048E-02 1.2029874297E-04 -6.0011725436E-03 + -1.7368502030E-02 4.8754907484E-03 -6.6068822619E-03 + 9.4161244751E-03 -1.3123955026E-03 9.3821004037E-03 + -1.8233633187E-03 -6.2724932591E-03 -3.7232834164E-04 + -3.5367123889E-03 1.3841568119E-03 5.1253182582E-04 + 1.0469002701E-02 4.5582556009E-03 -4.0047320189E-04 + 6.6647502247E-04 1.3566470593E-03 -4.2471475816E-04 + -2.3193062412E-02 -4.2669109670E-04 -9.1621091496E-03 + 1.4374148019E-02 -3.9292046076E-03 1.7401607626E-02 + 1.4361935888E-03 7.3111747542E-04 2.8939716585E-03 + 7.4942355276E-03 1.5334093054E-04 -2.3718729383E-03 + -4.4467595242E-03 2.2909459685E-03 3.7050279751E-04 + -5.7551546165E-03 -5.3104568036E-03 2.5626241618E-03 + 1.0311596639E-02 -6.3411631802E-03 -1.7273595557E-03 + -9.9758899927E-04 -3.4716657746E-04 2.6213593712E-03 + 1.0305825375E-02 -1.7020844108E-03 -2.9403707631E-03 + -5.9525094274E-03 9.1348120458E-04 1.0844847886E-02 + 1.2346671120E-03 -4.2455794777E-03 -1.3497654260E-02 + -1.7755664576E-02 1.1193664377E-02 1.5117104517E-03 + 2.0342208396E-02 -3.2716315115E-03 2.1149945211E-03 + 4.1413770940E-04 4.3517275418E-04 1.5465099113E-02 + 2.3330161951E-03 -1.8510869923E-03 -1.5551535299E-02 + -1.8353934854E-02 1.6812956207E-03 5.2598618976E-03 + 1.6689982848E-03 3.8432542244E-03 -1.1975571683E-02 + -1.0550403502E-02 -5.9287056575E-04 7.2227844057E-03 + 1.4068275760E-02 1.4295984271E-03 -3.9003854586E-03 + -2.2200953970E-03 -3.3933723888E-03 1.1442503450E-02 + 9.6515908616E-03 5.4458149186E-03 -1.2843277584E-02 + -2.5601349745E-02 4.4407907175E-03 -2.4611245672E-03 + 1.6815236076E-02 9.1016105318E-04 -8.1396673908E-03 + -2.9126567721E-03 -1.3585022581E-03 1.0134982086E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6148589356E+03 +:LATVEC_SCALE: + 1.5347245893E+01 1.5347245893E+01 1.5347245893E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0849897001E+00 1.5890568048E-02 -2.3405135874E-02 + 1.5890568048E-02 7.4997164522E-01 1.7194888219E-01 + -2.3405135874E-02 1.7194888219E-01 9.0939180374E-01 +:STRESS: + -1.8320131096E+00 -3.6954097725E-01 1.3982614249E+00 + -3.6954097725E-01 1.7048085961E+00 3.7057824120E-02 + 1.3982614249E+00 3.7057824120E-02 -6.5947692706E-01 +:CONSTRESS: + 3.4946869126E+00 7.5589960160E-01 -2.8080035230E+00 + 7.5589960160E-01 -4.3600677275E+00 2.7045110896E-01 + -2.8080035230E+00 2.7045110896E-01 8.6538081483E-01 +:TOTSTRESS: + -5.7768410290E-01 -3.7046805631E-01 1.3863369622E+00 + -3.7046805631E-01 3.4052307766E+00 -1.3556005089E-01 + 1.3863369622E+00 -1.3556005089E-01 7.0348791597E-01 +:PRESIO: 9.1478438303E-01 +:PRES: 2.6222714687E-01 +:CONPRES: -3.4722660360E-14 +:TOTPRES: 1.1770115299E+00 +:PRESIG: 9.4429355668E-01 +:MIND: +Al - Al: 4.6717257832E+00 +Si - Si: 4.7524491281E+00 +Al - Si: 4.8092102971E+00 + + +:MDSTEP: 29 +:MDTM: 13.67 +:TWIST: 0 +:TEL: 1120 +:TIO: 1146.94145485676 +:TEN: -3.2408281366E+00 +:KEN: 5.2779642805E-03 +:KENIG: 5.4482211928E-03 +:FEN: -3.2461061009E+00 +:UEN: -3.2453170906E+00 +:TSEN: -7.8901032004E-04 +:NPH_HAMIL: -8.1275609091E-05 +:NPH_ENTHALPY: -1.0368220777E+02 +:R: + 3.6478198742E-01 3.8306679573E-01 2.2205492863E-01 + 3.8952686887E+00 1.5336989516E+01 4.0950605711E+00 + 7.9856981809E+00 1.5184696429E+01 1.1868014105E-01 + 1.1376503338E+01 1.5341189233E+01 3.6352771261E+00 + 1.4589980496E-01 7.9117152777E+00 1.5346037728E+01 + 3.7405303519E+00 7.9073556122E+00 3.8106140111E+00 + 7.2948581779E+00 7.4252269545E+00 1.4688382841E-01 + 1.1537897970E+01 7.7816490674E+00 4.0312508054E+00 + 5.6240698194E-01 1.5170225783E+01 7.7440233351E+00 + 3.6472045474E+00 3.1435481785E-02 1.1238846883E+01 + 7.6978813718E+00 4.8116317403E-02 7.8180128397E+00 + 1.1588268779E+01 1.5174634179E+01 1.1754905204E+01 + 2.8283327195E-01 7.7031768483E+00 7.8775807782E+00 + 4.2189384936E+00 7.8825323244E+00 1.1491507222E+01 + 7.3337693371E+00 8.0000267844E+00 7.5414094622E+00 + 1.1539965783E+01 7.2818204143E+00 1.1496981569E+01 + 8.8695470553E-02 3.9310461650E+00 3.9366965426E+00 + 3.7258811357E+00 3.8693915242E+00 8.2625713363E-03 + 7.8424834237E+00 3.6410826840E+00 3.4316159647E+00 + 1.1384181090E+01 3.8128566895E+00 1.5212344273E+01 + 3.3254164374E-01 1.1434954591E+01 3.9179166675E+00 + 3.6242013277E+00 1.1570458391E+01 4.9402210683E-01 + 7.8404050407E+00 1.1699249412E+01 3.8511364155E+00 + 1.1067426551E+01 1.1513953941E+01 7.2068908075E-02 + 1.3775166825E-01 3.7118603180E+00 1.1256098845E+01 + 3.8219820609E+00 3.7024854786E+00 7.9643808010E+00 + 7.9219298017E+00 3.7727449065E+00 1.1546155493E+01 + 1.1376386337E+01 3.9653226638E+00 7.8260879080E+00 + 3.0140631321E-01 1.1533148248E+01 1.1518777891E+01 + 3.6963078315E+00 1.1258859503E+01 7.8531643053E+00 + 7.8526556037E+00 1.1748663814E+01 1.1713537532E+01 + 1.1634204902E+01 1.1540914916E+01 7.8309867821E+00 +:V: + -9.0300072140E-05 5.0763777672E-04 3.0411363838E-04 + 1.4262227108E-04 -3.6643265233E-05 3.2250960776E-04 + 3.4105323754E-04 -2.3528021713E-04 -3.0594014237E-04 + -1.5870426503E-04 -4.2763778031E-05 -2.3740662261E-04 + 1.9788650383E-04 2.7871303499E-04 -3.3950431404E-05 + -1.6087447796E-04 3.1539884175E-04 -3.5868121482E-05 + -4.8315196015E-04 -3.3818292032E-04 2.1382005874E-04 + 1.4005157515E-05 1.3646991988E-04 2.5294915423E-04 + 7.6537645334E-05 -2.7240721971E-04 3.9825352896E-05 + -1.9286887368E-04 3.4794808805E-05 -3.1567389711E-04 + 3.0684997215E-05 6.5006278553E-05 -2.3909547816E-04 + 1.2329075123E-04 -2.6272511267E-04 3.1751145016E-04 + 3.8554994665E-04 4.0560252455E-05 2.7369471106E-04 + 4.8566314418E-04 2.4305915659E-04 -4.5244452189E-05 + -4.4316467082E-04 4.0761745048E-04 -1.9603820296E-04 + 3.6345917723E-06 -5.7203461664E-04 -2.6638957908E-05 + 1.6732118837E-04 1.0788769835E-04 1.2239119482E-04 + -1.8968316809E-04 4.1553401502E-05 8.6062125744E-05 + 2.4285075182E-04 -2.9438969453E-04 -6.6271994787E-04 + -2.9617367103E-04 1.7534086664E-05 -2.1437563199E-04 + 1.6437289373E-04 -1.4232173124E-04 1.0078154894E-04 + -3.1622885813E-04 5.7592955235E-05 7.2257094937E-05 + 2.5741071060E-04 2.3276766956E-04 -1.0276241968E-04 + -7.8035775761E-04 7.1284706451E-06 1.5576194691E-04 + 2.1122675897E-04 -1.6090793433E-04 -4.4659822466E-04 + -9.1852101255E-05 -1.9815084695E-04 4.6330318454E-04 + 4.1735046016E-04 -8.2299147730E-05 -1.9345576125E-06 + -2.2180988330E-04 1.5881295787E-04 2.5009671809E-04 + 6.1518920028E-05 3.1796940899E-05 -1.0415454268E-04 + -3.5260758315E-04 -3.6534745162E-04 -4.7626197873E-04 + 3.5416950518E-04 3.1127885918E-04 1.9206417981E-04 + 1.1130945870E-04 1.8421062854E-05 2.8885948507E-04 +:F: + -1.1147537521E-03 -5.4865070821E-03 -1.3965758641E-03 + 1.0820732511E-02 2.2958923995E-05 -6.1122725207E-03 + -1.8096786651E-02 5.2950986054E-03 -6.6337565080E-03 + 9.6545253092E-03 -1.3148434892E-03 9.6319788215E-03 + -1.8506746925E-03 -6.2568980047E-03 -3.8287513324E-04 + -3.5540637469E-03 1.3808828220E-03 3.1416856083E-04 + 1.0510136425E-02 4.6134613445E-03 -6.5121500086E-04 + 8.2489972187E-04 1.4737867982E-03 -1.5507404442E-04 + -2.3514133548E-02 -6.0786560220E-04 -9.4065203389E-03 + 1.4681871331E-02 -4.2751335200E-03 1.7995748444E-02 + 1.4293563835E-03 9.3929310626E-04 3.1550486131E-03 + 7.8267795131E-03 5.2731244797E-05 -2.6517174852E-03 + -4.8998104377E-03 2.1997357848E-03 3.3541400353E-04 + -5.5911199340E-03 -5.2603043428E-03 2.8821513708E-03 + 1.0715305465E-02 -6.5239608988E-03 -2.0110676679E-03 + -7.5734049929E-04 -1.2567895095E-04 2.6621249018E-03 + 1.0644157173E-02 -1.5398830868E-03 -3.1490244134E-03 + -6.2146939902E-03 1.0173398922E-03 1.0742239162E-02 + 1.1560336276E-03 -4.4784075070E-03 -1.3350946884E-02 + -1.8020750761E-02 1.1319809668E-02 1.6181019381E-03 + 2.0150490029E-02 -3.3345509891E-03 2.2163696660E-03 + 5.7407923823E-04 5.5566668914E-04 1.5489671390E-02 + 1.9422035690E-03 -1.9505155095E-03 -1.5287049930E-02 + -1.7610748700E-02 1.2248331280E-03 5.0992595843E-03 + 1.3907108964E-03 3.8847761432E-03 -1.1897453514E-02 + -1.0473399789E-02 -4.7784718440E-04 6.6379101106E-03 + 1.4050673431E-02 1.2051599607E-03 -3.8175752824E-03 + -2.3169878332E-03 -3.5810126399E-03 1.1513124181E-02 + 9.5809212647E-03 5.7030633915E-03 -1.2667014605E-02 + -2.5743866218E-02 4.9099281868E-03 -2.5137916468E-03 + 1.6391864388E-02 9.3241616536E-04 -8.0778524484E-03 + -2.5856097236E-03 -1.5175330478E-03 9.8684725388E-03 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6297548124E+03 +:LATVEC_SCALE: + 1.5368297649E+01 1.5368297649E+01 1.5368297649E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0874313906E+00 1.8497864567E-02 -2.7564850633E-02 + 1.8497864567E-02 7.4027576827E-01 1.7112695272E-01 + -2.7564850633E-02 1.7112695272E-01 9.1025090994E-01 +:STRESS: + -1.6168147918E+00 -3.8018261845E-01 1.4177228683E+00 + -3.8018261845E-01 1.7820824088E+00 3.7303161935E-02 + 1.4177228683E+00 3.7303161935E-02 -3.9022785834E-01 +:CONSTRESS: + 3.4456374024E+00 7.8155013411E-01 -2.8574431080E+00 + 7.8155013411E-01 -4.1476774318E+00 2.6875744747E-01 + -2.8574431080E+00 2.6875744747E-01 7.0204002943E-01 +:TOTSTRESS: + -7.4139122001E-01 -3.8286965109E-01 1.4121553890E+00 + -3.8286965109E-01 3.1058707913E+00 -1.3493365669E-01 + 1.4121553890E+00 -1.3493365669E-01 5.9843873884E-01 +:PRESIO: 9.1265268959E-01 +:PRES: 7.4986747113E-02 +:CONPRES: -9.1209284870E-14 +:TOTPRES: 9.8763943670E-01 +:PRESIG: 9.4209309893E-01 +:MIND: +Al - Al: 4.6671663005E+00 +Si - Si: 4.7514670069E+00 +Al - Si: 4.7930755018E+00 + + +:MDSTEP: 30 +:MDTM: 13.59 +:TWIST: 0 +:TEL: 1120 +:TIO: 1149.05537732715 +:TEN: -3.2408420778E+00 +:KEN: 5.2876920720E-03 +:KENIG: 5.4582627840E-03 +:FEN: -3.2461297699E+00 +:UEN: -3.2453525676E+00 +:TSEN: -7.7720224788E-04 +:NPH_HAMIL: -6.8623306191E-05 +:NPH_ENTHALPY: -1.0368219512E+02 +:R: + 3.6303553854E-01 3.9617041785E-01 2.2990657731E-01 + 3.9042556407E+00 1.5357248862E+01 4.1086854659E+00 + 8.0050787987E+00 1.5199844634E+01 1.1120313689E-01 + 1.1388324538E+01 1.5361293969E+01 3.6344582094E+00 + 1.5100491143E-01 7.9295194648E+00 1.5366373909E+01 + 3.7416751107E+00 7.9261128616E+00 3.8149847744E+00 + 7.2929919356E+00 7.4271046193E+00 1.5239358044E-01 + 1.1554176577E+01 7.7957889616E+00 4.0430971209E+00 + 5.6493710616E-01 1.5184394841E+01 7.7556425864E+00 + 3.6475399996E+00 3.2316364909E-02 1.1246631346E+01 + 7.7092777664E+00 4.9803309731E-02 7.8228847646E+00 + 1.1607375320E+01 1.5189053955E+01 1.1779000379E+01 + 2.9276967105E-01 7.7148306694E+00 7.8952544902E+00 + 4.2367902200E+00 7.8994168639E+00 1.1506262977E+01 + 7.3329513351E+00 8.0211530583E+00 7.5469367407E+00 + 1.1555979739E+01 7.2776617974E+00 1.1512205645E+01 + 9.3038046573E-02 3.9391426846E+00 3.9451514318E+00 + 3.7262749583E+00 3.8757706490E+00 1.0476318515E-02 + 7.8593474118E+00 3.6387690967E+00 3.4198108868E+00 + 1.1392429369E+01 3.8186231567E+00 1.5228026461E+01 + 3.3720476676E-01 1.1447182862E+01 3.9258411574E+00 + 3.6213523778E+00 1.1587862798E+01 4.9659200272E-01 + 7.8576325464E+00 1.1721167681E+01 3.8538075639E+00 + 1.1063213408E+01 1.1530030891E+01 7.6068048313E-02 + 1.4319684746E-01 3.7130103099E+00 1.1260470776E+01 + 3.8249129356E+00 3.7026712001E+00 7.9869218601E+00 + 7.9433154491E+00 3.7759153807E+00 1.1562021432E+01 + 1.1386565479E+01 3.9747191480E+00 7.8431715711E+00 + 3.0340806345E-01 1.1549891381E+01 1.1532013741E+01 + 3.6924964307E+00 1.1265354573E+01 7.8521588679E+00 + 7.8723903654E+00 1.1772617781E+01 1.1734427616E+01 + 1.1653012662E+01 1.1557293076E+01 7.8490301414E+00 +:V: + -9.0680833462E-05 5.0415954859E-04 3.0298332675E-04 + 1.4787514471E-04 -3.6604780505E-05 3.1895912522E-04 + 3.3127983636E-04 -2.3217418912E-04 -3.0886552121E-04 + -1.5356413701E-04 -4.3366060037E-05 -2.3216418618E-04 + 1.9667771150E-04 2.7518203524E-04 -3.4100963757E-05 + -1.6244371712E-04 3.1565398795E-04 -3.5712312784E-05 + -4.7718346787E-04 -3.3538147232E-04 2.1313266001E-04 + 1.4442219805E-05 1.3705242299E-04 2.5259391871E-04 + 6.4508689128E-05 -2.7238447953E-04 3.4973895698E-05 + -1.8513109887E-04 3.2505724393E-05 -3.0602400816E-04 + 3.1362935507E-05 6.5442324754E-05 -2.3711285460E-04 + 1.2715001722E-04 -2.6236121690E-04 3.1566747800E-04 + 3.8243299730E-04 4.1583551652E-05 2.7347817825E-04 + 4.8222010692E-04 2.4009088889E-04 -4.3649486157E-05 + -4.3705662135E-04 4.0372404639E-04 -1.9685374104E-04 + 3.3106491934E-06 -5.7124993955E-04 -2.5250337711E-05 + 1.7232080024E-04 1.0703226673E-04 1.2064711442E-04 + -1.9249547904E-04 4.2013687089E-05 9.1117108381E-05 + 2.4306663111E-04 -2.9620547585E-04 -6.6823564055E-04 + -3.0455092336E-04 2.3014679090E-05 -2.1326634638E-04 + 1.7384588170E-04 -1.4375131502E-04 1.0173550636E-04 + -3.1547920407E-04 5.7811690624E-05 7.9659609449E-05 + 2.5790575314E-04 2.3147787850E-04 -1.0995546813E-04 + -7.8762147938E-04 7.5959275942E-06 1.5798246710E-04 + 2.1154157791E-04 -1.5879675917E-04 -4.5171889205E-04 + -9.6775238479E-05 -1.9807649623E-04 4.6573608718E-04 + 4.2356693440E-04 -8.1660262361E-05 -3.7593504791E-06 + -2.2265020944E-04 1.5681601084E-04 2.5532954715E-04 + 6.6059802795E-05 3.4573639737E-05 -1.1010150880E-04 + -3.6461170951E-04 -3.6235319232E-04 -4.7682467894E-04 + 3.6150646853E-04 3.1130243901E-04 1.8789811995E-04 + 1.0998260458E-04 1.7621872413E-05 2.9317602120E-04 +:F: + -8.9037385718E-04 -5.5398132751E-03 -1.4254719379E-03 + 1.0805151436E-02 -7.0609490636E-05 -6.2134077068E-03 + -1.8822322531E-02 5.7436966793E-03 -6.6489299973E-03 + 9.8755077589E-03 -1.3092006712E-03 9.8735413376E-03 + -1.8638950099E-03 -6.2311217333E-03 -4.0020153365E-04 + -3.5533589946E-03 1.3569057620E-03 1.0809192225E-04 + 1.0532612830E-02 4.6540269323E-03 -9.0691010467E-04 + 9.8605415878E-04 1.5842606606E-03 1.2878444395E-04 + -2.3803223169E-02 -7.9183833529E-04 -9.6282091882E-03 + 1.4969845736E-02 -4.6184007611E-03 1.8572138037E-02 + 1.4288506252E-03 1.1465740079E-03 3.4048484708E-03 + 8.1626665744E-03 -4.5676556718E-05 -2.9289933257E-03 + -5.3603383717E-03 2.0831140153E-03 3.0242730882E-04 + -5.4159067988E-03 -5.1896042256E-03 3.1996721191E-03 + 1.1099750201E-02 -6.6969922949E-03 -2.2974842104E-03 + -5.0849725472E-04 1.1041908407E-04 2.7027904738E-03 + 1.0960399875E-02 -1.3795090589E-03 -3.3583102776E-03 + -6.4820499812E-03 1.1205026145E-03 1.0628669336E-02 + 1.1184601319E-03 -4.6981358771E-03 -1.3206390347E-02 + -1.8269656396E-02 1.1418855103E-02 1.7433842682E-03 + 1.9916010657E-02 -3.3809965447E-03 2.2979464791E-03 + 7.2192237046E-04 6.7570816901E-04 1.5499592078E-02 + 1.5685730331E-03 -2.0518888840E-03 -1.5010850272E-02 + -1.6837472676E-02 7.4702679729E-04 4.9600930442E-03 + 1.1125841796E-03 3.9197475701E-03 -1.1797567526E-02 + -1.0385838300E-02 -3.4333966197E-04 6.0501054312E-03 + 1.4004274323E-02 9.6548508481E-04 -3.7312427812E-03 + -2.4170371144E-03 -3.7634909500E-03 1.1526302921E-02 + 9.5265914215E-03 5.9476302642E-03 -1.2491501202E-02 + -2.5849630366E-02 5.3780636694E-03 -2.5222778030E-03 + 1.5932081570E-02 9.3732051977E-04 -8.0375209929E-03 + -2.2617360603E-03 -1.6787186126E-03 9.6068815356E-03 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6448058352E+03 +:LATVEC_SCALE: + 1.5389510250E+01 1.5389510250E+01 1.5389510250E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0900349920E+00 2.1072347314E-02 -3.1463748480E-02 + 2.1072347314E-02 7.3058531476E-01 1.7025141181E-01 + -3.1463748480E-02 1.7025141181E-01 9.1105699589E-01 +:STRESS: + -1.4088154172E+00 -3.9160016002E-01 1.4348265773E+00 + -3.9160016002E-01 1.8622477917E+00 3.7979932871E-02 + 1.4348265773E+00 3.7979932871E-02 -1.3327288784E-01 +:CONSTRESS: + 3.4007722609E+00 8.0870272916E-01 -2.9018667991E+00 + 8.0870272916E-01 -3.9519901503E+00 2.6614696341E-01 + -2.9018667991E+00 2.6614696341E-01 5.5121788937E-01 +:TOTSTRESS: + -9.0192185167E-01 -3.9603022182E-01 1.4355764734E+00 + -3.9603022182E-01 2.8203276734E+00 -1.3387548446E-01 + 1.4355764734E+00 -1.3387548446E-01 4.9311199436E-01 +:PRESIO: 9.1055910088E-01 +:PRES: -1.0671982885E-01 +:CONPRES: 9.1608013984E-14 +:TOTPRES: 8.0383927202E-01 +:PRESIG: 9.3993197510E-01 +:MIND: +Al - Al: 4.6632410364E+00 +Si - Si: 4.7502806380E+00 +Al - Si: 4.7771282865E+00 diff --git a/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.refout b/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.refout new file mode 100644 index 00000000..519f5388 --- /dev/null +++ b/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.refout @@ -0,0 +1,597 @@ +*************************************************************************** +* SPARC (version December 03, 2025) * +* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * +* Distributed under GNU General Public License 3 (GPL) * +* Start time: Mon Apr 6 12:34:13 2026 * +*************************************************************************** + Input parameters +*************************************************************************** +LATVEC_SCALE: 15 15 15 +LATVEC: +1.000000000000000 0.000000000000000 0.000000000000000 +0.000000000000000 1.000000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 +FD_GRID: 75 75 75 +FD_ORDER: 12 +BC: P P P +KPOINT_GRID: 1 1 1 +KPOINT_SHIFT: 0 0 0 +SPIN_TYP: 0 +ELEC_TEMP_TYPE: Fermi-Dirac +ELEC_TEMP: 1120 +EXCHANGE_CORRELATION: GGA_PBE +HUBBARD_FLAG: 0 +NSTATES: 76 +CHEB_DEGREE: 35 +CHEFSI_BOUND_FLAG: 0 +CALC_STRESS: 1 +TWTIME: 1E+09 +MD_FLAG: 1 +MD_METHOD: NPH +MD_TIMESTEP: 0.6 +MD_NSTEP: 10 +ION_VEL_DSTR: 2 +ION_VEL_DSTR_RAND: 0 +ION_TEMP: 1120 +NPH_SCALE_VECS: 1 2 3 +NPH_SCALE_CONSTRAINTS: 123 +NPH_ANGLES: 0 +NPH_BMASS: 0.1 +TARGET_STRESS: 0 0 0 0 0 0 GPa +RESTART_FLAG: 1 +MAXIT_SCF: 100 +MINIT_SCF: 2 +MAXIT_POISSON: 3000 +TOL_SCF: 5.00E-07 +POISSON_SOLVER: AAR +TOL_POISSON: 5.00E-09 +TOL_LANCZOS: 1.00E-02 +TOL_PSEUDOCHARGE: 5.00E-10 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +TOL_PRECOND: 4.00E-05 +PRECOND_KERKER_KTF: 1 +PRECOND_KERKER_THRESH: 0 +MIXING_PARAMETER: 1 +MIXING_HISTORY: 7 +PULAY_FREQUENCY: 1 +PULAY_RESTART: 0 +REFERENCE_CUTOFF: 0.5 +RHO_TRIGGER: 4 +NUM_CHEFSI: 1 +FIX_RAND: 0 +VERBOSITY: 1 +PRINT_FORCES: 1 +PRINT_ATOMS: 1 +PRINT_EIGEN: 0 +PRINT_DENSITY: 0 +PRINT_MDOUT: 1 +PRINT_VELS: 1 +PRINT_RESTART: 1 +PRINT_RESTART_FQ: 1 +PRINT_ENERGY_DENSITY: 0 +OUTPUT_FILE: Al16Si16_NPH_restart +*************************************************************************** + Cell +*************************************************************************** +Lattice vectors (Bohr): +15.000000000000000 0.000000000000000 0.000000000000000 +0.000000000000000 15.000000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 15.000000000000000 +Volume: 3.3750000000E+03 (Bohr^3) +Density: 2.6105618252E-01 (amu/Bohr^3), 2.9253624436E+00 (g/cc) +*************************************************************************** + Parallelization +*************************************************************************** +NP_SPIN_PARAL: 1 +NP_KPOINT_PARAL: 1 +NP_BAND_PARAL: 7 +NP_DOMAIN_PARAL: 5 1 1 +NP_DOMAIN_PHI_PARAL: 3 3 4 +EIG_SERIAL_MAXNS: 1500 +*************************************************************************** + Initialization +*************************************************************************** +Number of processors : 36 +Mesh spacing : 0.2 (Bohr) +Number of symmetry adapted k-points: 1 +Output printed to : Al16Si16_NPH_restart.out_01 +MD output printed to : Al16Si16_NPH_restart.aimd_01 +Total number of atom types : 2 +Total number of atoms : 32 +Total number of electrons : 112 +Atom type 1 (valence electrons) : Al 3 +Pseudopotential : ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +Atomic mass : 26.9815385 +Pseudocharge radii of atom type 1 : 7.20 7.20 7.20 (x, y, z dir) +Number of atoms of type 1 : 16 +Atom type 2 (valence electrons) : Si 4 +Pseudopotential : ../../../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 +Atomic mass : 28.085 +Pseudocharge radii of atom type 2 : 7.20 7.20 7.20 (x, y, z dir) +Number of atoms of type 2 : 16 +Estimated total memory usage : 1.81 GB +Estimated memory per processor : 51.36 MB +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.208200323 15.208200323 15.208200323 +CHEB_DEGREE: 35 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.202776 (Bohr) +=================================================================== + Self Consistent Field (SCF#20) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2260277497E+00 1.274E-01 5.573 +2 -3.2401511948E+00 4.206E-02 1.529 +3 -3.2437111711E+00 2.258E-02 1.553 +4 -3.2449770424E+00 1.593E-02 1.497 +5 -3.2454939945E+00 9.649E-03 1.519 +6 -3.2457000992E+00 5.289E-03 1.486 +7 -3.2457786768E+00 2.514E-03 1.476 +8 -3.2458099466E+00 1.195E-03 1.510 +9 -3.2458221867E+00 5.555E-04 1.488 +10 -3.2458269432E+00 3.702E-04 1.485 +11 -3.2458287429E+00 1.959E-04 1.484 +12 -3.2458294103E+00 1.075E-04 1.452 +13 -3.2458296613E+00 1.486E-04 1.436 +14 -3.2458297486E+00 3.737E-05 1.440 +15 -3.2458297804E+00 2.006E-05 1.436 +16 -3.2458297924E+00 3.784E-05 1.466 +17 -3.2458297961E+00 9.030E-06 1.429 +18 -3.2458297978E+00 1.136E-05 1.439 +19 -3.2458297984E+00 9.560E-07 1.400 +20 -3.2458297987E+00 1.595E-06 1.380 +21 -3.2458297988E+00 1.999E-06 1.418 +22 -3.2458297987E+00 3.200E-06 1.422 +23 -3.2458297988E+00 2.142E-06 1.395 +24 -3.2458297987E+00 2.245E-06 1.416 +25 -3.2458297988E+00 2.193E-06 1.416 +26 -3.2458297988E+00 1.867E-06 1.425 +27 -3.2458297988E+00 6.088E-07 1.371 +28 -3.2458297987E+00 4.621E-07 1.388 +Total number of SCF: 28 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2458297987E+00 (Ha/atom) +Total free energy : -1.0386655356E+02 (Ha) +Band structure energy : 5.1432791192E+00 (Ha) +Exchange correlation energy : -4.1882229457E+01 (Ha) +Self and correction energy : -1.6501201600E+02 (Ha) +-Entropy*kb*T : -2.9743534434E-02 (Ha) +Fermi level : 2.0512260234E-01 (Ha) +RMS force : 1.2181785195E-02 (Ha/Bohr) +Maximum force : 2.3689047837E-02 (Ha/Bohr) +Time for force calculation : 0.129 (sec) +Pressure : 1.6338289664E+00 (GPa) +Maximum stress : 3.4876435924E+00 (GPa) +Time for stress calculation : 0.251 (sec) +MD step time : 45.450 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.2268419085932 15.2268419085932 15.2268419085932 +CHEB_DEGREE: 35 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.203025 (Bohr) +=================================================================== + Self Consistent Field (SCF#21) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2459397458E+00 1.442E-02 1.503 +2 -3.2458774557E+00 5.865E-03 1.547 +3 -3.2458727263E+00 2.452E-03 1.474 +4 -3.2458715472E+00 8.125E-04 1.455 +5 -3.2458714149E+00 1.114E-04 1.481 +6 -3.2458714130E+00 2.314E-05 1.496 +7 -3.2458714117E+00 1.111E-05 1.411 +8 -3.2458714131E+00 3.705E-06 1.446 +9 -3.2458714123E+00 1.311E-06 1.382 +10 -3.2458714125E+00 3.409E-07 1.407 +Total number of SCF: 10 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2458714125E+00 (Ha/atom) +Total free energy : -1.0386788520E+02 (Ha) +Band structure energy : 5.0387581472E+00 (Ha) +Exchange correlation energy : -4.1855530588E+01 (Ha) +Self and correction energy : -1.6501201141E+02 (Ha) +-Entropy*kb*T : -2.9067158173E-02 (Ha) +Fermi level : 2.0404101471E-01 (Ha) +RMS force : 1.2332003940E-02 (Ha/Bohr) +Maximum force : 2.4053129017E-02 (Ha/Bohr) +Time for force calculation : 0.128 (sec) +Pressure : 1.4402698551E+00 (GPa) +Maximum stress : 3.2416072913E+00 (GPa) +Time for stress calculation : 0.248 (sec) +MD step time : 15.179 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.2459709976216 15.2459709976216 15.2459709976216 +CHEB_DEGREE: 35 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.20328 (Bohr) +=================================================================== + Self Consistent Field (SCF#22) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2459801635E+00 1.443E-02 1.574 +2 -3.2459171952E+00 5.728E-03 1.542 +3 -3.2459127910E+00 2.378E-03 1.542 +4 -3.2459117002E+00 8.127E-04 1.507 +5 -3.2459115678E+00 1.087E-04 1.516 +6 -3.2459115660E+00 2.266E-05 1.492 +7 -3.2459115647E+00 1.032E-05 1.464 +8 -3.2459115661E+00 3.630E-06 1.471 +9 -3.2459115653E+00 1.338E-06 1.412 +10 -3.2459115655E+00 3.566E-07 1.454 +Total number of SCF: 10 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2459115655E+00 (Ha/atom) +Total free energy : -1.0386917010E+02 (Ha) +Band structure energy : 4.9315308511E+00 (Ha) +Exchange correlation energy : -4.1828351453E+01 (Ha) +Self and correction energy : -1.6501200725E+02 (Ha) +-Entropy*kb*T : -2.8417811469E-02 (Ha) +Fermi level : 2.0293316186E-01 (Ha) +RMS force : 1.2470807862E-02 (Ha/Bohr) +Maximum force : 2.4474056256E-02 (Ha/Bohr) +Time for force calculation : 0.129 (sec) +Pressure : 1.2436763191E+00 (GPa) +Maximum stress : 2.9968762220E+00 (GPa) +Time for stress calculation : 0.246 (sec) +MD step time : 15.555 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.2655392801998 15.2655392801998 15.2655392801998 +CHEB_DEGREE: 35 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.203541 (Bohr) +=================================================================== + Self Consistent Field (SCF#23) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2459459673E+00 1.834E-03 1.484 +2 -3.2459498487E+00 2.629E-04 1.439 +3 -3.2459499195E+00 1.157E-04 1.465 +4 -3.2459499262E+00 4.692E-05 1.454 +5 -3.2459499269E+00 2.838E-05 1.478 +6 -3.2459499273E+00 8.844E-06 1.477 +7 -3.2459499277E+00 3.763E-06 1.448 +8 -3.2459499278E+00 1.125E-06 1.429 +9 -3.2459499275E+00 4.138E-07 1.426 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2459499275E+00 (Ha/atom) +Total free energy : -1.0387039768E+02 (Ha) +Band structure energy : 4.8218725044E+00 (Ha) +Exchange correlation energy : -4.1800785672E+01 (Ha) +Self and correction energy : -1.6501200361E+02 (Ha) +-Entropy*kb*T : -2.7798087876E-02 (Ha) +Fermi level : 2.0180109616E-01 (Ha) +RMS force : 1.2598038647E-02 (Ha/Bohr) +Maximum force : 2.4863216727E-02 (Ha/Bohr) +Time for force calculation : 0.129 (sec) +Pressure : 1.0454080868E+00 (GPa) +Maximum stress : 2.7546669434E+00 (GPa) +Time for stress calculation : 0.246 (sec) +MD step time : 13.682 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.2854984698912 15.2854984698912 15.2854984698912 +CHEB_DEGREE: 35 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.203807 (Bohr) +=================================================================== + Self Consistent Field (SCF#24) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2459821647E+00 1.845E-03 1.514 +2 -3.2459861121E+00 2.747E-04 1.443 +3 -3.2459861845E+00 1.294E-04 1.491 +4 -3.2459861894E+00 5.850E-05 1.462 +5 -3.2459861904E+00 3.090E-05 1.480 +6 -3.2459861910E+00 6.515E-06 1.450 +7 -3.2459861912E+00 4.005E-06 1.471 +8 -3.2459861912E+00 1.334E-06 1.468 +9 -3.2459861908E+00 4.247E-07 1.423 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2459861908E+00 (Ha/atom) +Total free energy : -1.0387155811E+02 (Ha) +Band structure energy : 4.7100602035E+00 (Ha) +Exchange correlation energy : -4.1772926676E+01 (Ha) +Self and correction energy : -1.6501200004E+02 (Ha) +-Entropy*kb*T : -2.7210822288E-02 (Ha) +Fermi level : 2.0064685576E-01 (Ha) +RMS force : 1.2713493481E-02 (Ha/Bohr) +Maximum force : 2.5220603921E-02 (Ha/Bohr) +Time for force calculation : 0.125 (sec) +Pressure : 8.4684140675E-01 (GPa) +Maximum stress : 2.5161520545E+00 (GPa) +Time for stress calculation : 0.238 (sec) +MD step time : 13.763 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.3058006402421 15.3058006402421 15.3058006402421 +CHEB_DEGREE: 35 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.204077 (Bohr) +=================================================================== + Self Consistent Field (SCF#25) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2540982700E+00 9.888E-01 1.546 +2 -3.2462475192E+00 6.691E-02 1.539 +3 -3.2462080905E+00 3.182E-02 1.490 +4 -3.2460606123E+00 1.415E-02 1.544 +5 -3.2460209745E+00 2.745E-03 1.506 +6 -3.2460200587E+00 9.195E-04 1.515 +7 -3.2460200161E+00 2.759E-04 1.502 +8 -3.2460200354E+00 9.765E-05 1.505 +9 -3.2460200430E+00 3.094E-05 1.492 +10 -3.2460200465E+00 1.326E-05 1.449 +11 -3.2460200473E+00 6.692E-06 1.444 +12 -3.2460200475E+00 2.482E-06 1.480 +13 -3.2460200479E+00 5.742E-07 1.458 +14 -3.2460200479E+00 1.425E-06 1.468 +15 -3.2460200480E+00 7.718E-07 1.453 +16 -3.2460200479E+00 6.229E-07 1.409 +17 -3.2460200479E+00 4.345E-07 1.420 +Total number of SCF: 17 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2460200479E+00 (Ha/atom) +Total free energy : -1.0387264153E+02 (Ha) +Band structure energy : 4.5963678589E+00 (Ha) +Exchange correlation energy : -4.1744866429E+01 (Ha) +Self and correction energy : -1.6501199615E+02 (Ha) +-Entropy*kb*T : -2.6659003136E-02 (Ha) +Fermi level : 1.9947246756E-01 (Ha) +RMS force : 1.2817442532E-02 (Ha/Bohr) +Maximum force : 2.5546080375E-02 (Ha/Bohr) +Time for force calculation : 0.125 (sec) +Pressure : 6.4930601415E-01 (GPa) +Maximum stress : 2.2823437764E+00 (GPa) +Time for stress calculation : 0.237 (sec) +MD step time : 25.833 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.3263985427318 15.3263985427318 15.3263985427318 +CHEB_DEGREE: 35 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.204352 (Bohr) +=================================================================== + Self Consistent Field (SCF#26) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2460490285E+00 1.175E-03 1.470 +2 -3.2460512435E+00 2.761E-04 1.465 +3 -3.2460513126E+00 1.089E-04 1.431 +4 -3.2460513197E+00 4.329E-05 1.466 +5 -3.2460513210E+00 1.628E-05 1.451 +6 -3.2460513215E+00 9.302E-06 1.466 +7 -3.2460513219E+00 4.234E-06 1.426 +8 -3.2460513220E+00 1.048E-06 1.432 +9 -3.2460513218E+00 3.228E-07 1.436 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2460513218E+00 (Ha/atom) +Total free energy : -1.0387364230E+02 (Ha) +Band structure energy : 4.4810592419E+00 (Ha) +Exchange correlation energy : -4.1716694082E+01 (Ha) +Self and correction energy : -1.6501199188E+02 (Ha) +-Entropy*kb*T : -2.6145794979E-02 (Ha) +Fermi level : 1.9827989262E-01 (Ha) +RMS force : 1.2910454366E-02 (Ha/Bohr) +Maximum force : 2.5839064083E-02 (Ha/Bohr) +Time for force calculation : 0.125 (sec) +Pressure : 4.5402679811E-01 (GPa) +Maximum stress : 2.0540353446E+00 (GPa) +Time for stress calculation : 0.237 (sec) +MD step time : 13.601 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.3472458930614 15.3472458930614 15.3472458930614 +CHEB_DEGREE: 35 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.20463 (Bohr) +=================================================================== + Self Consistent Field (SCF#27) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2460776811E+00 1.154E-03 1.481 +2 -3.2460799131E+00 2.738E-04 1.431 +3 -3.2460799830E+00 1.096E-04 1.451 +4 -3.2460799902E+00 4.430E-05 1.449 +5 -3.2460799914E+00 2.004E-05 1.482 +6 -3.2460799919E+00 9.901E-06 1.439 +7 -3.2460799922E+00 4.172E-06 1.429 +8 -3.2460799924E+00 8.971E-07 1.439 +9 -3.2460799924E+00 3.863E-07 1.388 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2460799924E+00 (Ha/atom) +Total free energy : -1.0387455976E+02 (Ha) +Band structure energy : 4.3643928142E+00 (Ha) +Exchange correlation energy : -4.1688497344E+01 (Ha) +Self and correction energy : -1.6501198723E+02 (Ha) +-Entropy*kb*T : -2.5674468175E-02 (Ha) +Fermi level : 1.9707104751E-01 (Ha) +RMS force : 1.2992915727E-02 (Ha/Bohr) +Maximum force : 2.6099939945E-02 (Ha/Bohr) +Time for force calculation : 0.125 (sec) +Pressure : 2.6222714687E-01 (GPa) +Maximum stress : 1.8320131096E+00 (GPa) +Time for stress calculation : 0.237 (sec) +MD step time : 13.570 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.3682976492234 15.3682976492234 15.3682976492234 +CHEB_DEGREE: 35 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.204911 (Bohr) +=================================================================== + Self Consistent Field (SCF#28) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2461017395E+00 1.912E-03 1.485 +2 -3.2461060197E+00 2.779E-04 1.468 +3 -3.2461060932E+00 1.228E-04 1.458 +4 -3.2461060994E+00 5.050E-05 1.458 +5 -3.2461061003E+00 2.913E-05 1.455 +6 -3.2461061010E+00 7.840E-06 1.471 +7 -3.2461061011E+00 3.916E-06 1.461 +8 -3.2461061013E+00 1.154E-06 1.449 +9 -3.2461061009E+00 3.860E-07 1.412 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2461061009E+00 (Ha/atom) +Total free energy : -1.0387539523E+02 (Ha) +Band structure energy : 4.2466170087E+00 (Ha) +Exchange correlation energy : -4.1660360292E+01 (Ha) +Self and correction energy : -1.6501198254E+02 (Ha) +-Entropy*kb*T : -2.5248330241E-02 (Ha) +Fermi level : 1.9584778911E-01 (Ha) +RMS force : 1.3065548691E-02 (Ha/Bohr) +Maximum force : 2.6328182450E-02 (Ha/Bohr) +Time for force calculation : 0.124 (sec) +Pressure : 7.4986747113E-02 (GPa) +Maximum stress : 1.7820824088E+00 (GPa) +Time for stress calculation : 0.236 (sec) +MD step time : 13.674 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.3895102501726 15.3895102501726 15.3895102501726 +CHEB_DEGREE: 35 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.205193 (Bohr) +=================================================================== + Self Consistent Field (SCF#29) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2461253042E+00 1.939E-03 1.502 +2 -3.2461296885E+00 2.780E-04 1.462 +3 -3.2461297618E+00 1.202E-04 1.418 +4 -3.2461297682E+00 4.781E-05 1.449 +5 -3.2461297692E+00 2.572E-05 1.453 +6 -3.2461297697E+00 8.674E-06 1.455 +7 -3.2461297702E+00 3.897E-06 1.429 +8 -3.2461297701E+00 1.037E-06 1.460 +9 -3.2461297699E+00 4.055E-07 1.412 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2461297699E+00 (Ha/atom) +Total free energy : -1.0387615264E+02 (Ha) +Band structure energy : 4.1279695067E+00 (Ha) +Exchange correlation energy : -4.1632362724E+01 (Ha) +Self and correction energy : -1.6501197816E+02 (Ha) +-Entropy*kb*T : -2.4870471932E-02 (Ha) +Fermi level : 1.9461189609E-01 (Ha) +RMS force : 1.3129125702E-02 (Ha/Bohr) +Maximum force : 2.6523364119E-02 (Ha/Bohr) +Time for force calculation : 0.122 (sec) +Pressure : -1.0671982885E-01 (GPa) +Maximum stress : 1.8622477917E+00 (GPa) +Time for stress calculation : 0.231 (sec) +MD step time : 13.589 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.4108418243 15.4108418243 15.4108418243 +CHEB_DEGREE: 35 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.205478 (Bohr) +=================================================================== + Self Consistent Field (SCF#30) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2461466542E+00 1.941E-03 1.504 +2 -3.2461511170E+00 2.826E-04 1.456 +3 -3.2461511910E+00 1.232E-04 1.482 +4 -3.2461511971E+00 4.981E-05 1.436 +5 -3.2461511979E+00 2.797E-05 1.466 +6 -3.2461511987E+00 7.915E-06 1.472 +7 -3.2461511988E+00 3.935E-06 1.459 +8 -3.2461511990E+00 1.114E-06 1.432 +9 -3.2461511987E+00 3.950E-07 1.393 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2461511987E+00 (Ha/atom) +Total free energy : -1.0387683836E+02 (Ha) +Band structure energy : 4.0086778428E+00 (Ha) +Exchange correlation energy : -4.1604581073E+01 (Ha) +Self and correction energy : -1.6501197413E+02 (Ha) +-Entropy*kb*T : -2.4543556449E-02 (Ha) +Fermi level : 1.9336509153E-01 (Ha) +RMS force : 1.3184543151E-02 (Ha/Bohr) +Maximum force : 2.6684907902E-02 (Ha/Bohr) +Time for force calculation : 0.118 (sec) +Pressure : -2.8184974143E-01 (GPa) +Maximum stress : 1.9444102070E+00 (GPa) +Time for stress calculation : 0.224 (sec) +*************************************************************************** + Timing info +*************************************************************************** +Total walltime : 197.940 sec +___________________________________________________________________________ + +*************************************************************************** +* Material Physics & Mechanics Group, Georgia Tech * +* PI: Phanish Suryanarayana * +* List of contributors: See the documentation * +* Citation: See README.md or the documentation for details * +* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * +* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * +*************************************************************************** + diff --git a/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.restart b/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.restart new file mode 100644 index 00000000..ccbb7d73 --- /dev/null +++ b/tests/Al16Si16_NPH_restart/high_accuracy/Al16Si16_NPH_restart.restart @@ -0,0 +1,128 @@ +:MDSTEP: 20 +:R(Bohr): + 3.7821386612E-01 2.7610243971E-01 1.5877961297E-01 + 3.8306488250E+00 1.5184616989E+01 3.9859888361E+00 + 7.8282405005E+00 1.5074999344E+01 1.7563133011E-01 + 1.1293130908E+01 1.5189362369E+01 3.6481797039E+00 + 1.0436087852E-01 7.7713969978E+00 1.5192768445E+01 + 3.7321556689E+00 7.7628257450E+00 3.7783632147E+00 + 7.3190243007E+00 7.4168571310E+00 1.0285052253E-01 + 1.1415089306E+01 7.6739189176E+00 3.9386631094E+00 + 5.3229358748E-01 1.5066269254E+01 7.6519541746E+00 + 3.6530763425E+00 2.2842110153E-02 1.1191072798E+01 + 7.6121790176E+00 3.4856691517E-02 7.7850637292E+00 + 1.1445840575E+01 1.5068900197E+01 1.1568578988E+01 + 2.0176186061E-01 7.6158114362E+00 7.7412941179E+00 + 4.0760765696E+00 7.7499802251E+00 1.1381611206E+01 + 7.3492936068E+00 7.8332635406E+00 7.5012979993E+00 + 1.1418485849E+01 7.3193908223E+00 1.1383528878E+01 + 5.8239803863E-02 3.8678991419E+00 3.8703576117E+00 + 3.7226279205E+00 3.8211142119E+00 1.5203493003E+01 + 7.7131027467E+00 3.6601887305E+00 3.5222994422E+00 + 1.1317801763E+01 3.7738423895E+00 1.5097012359E+01 + 3.0429600490E-01 1.1342919572E+01 3.8577886293E+00 + 3.6493334170E+00 1.1438569231E+01 4.8043006716E-01 + 7.7087343844E+00 1.1530457410E+01 3.8253060061E+00 + 1.1099755188E+01 1.1393487696E+01 4.2523023204E-02 + 9.5147217373E-02 3.7066161661E+00 1.1222982683E+01 + 3.7963361440E+00 3.7030249293E+00 7.7924678577E+00 + 7.7618427489E+00 3.7504643080E+00 1.1424711522E+01 + 1.1301155961E+01 3.8912676307E+00 7.6991262943E+00 + 2.8982176377E-01 1.1408607979E+01 1.1414432425E+01 + 3.7181667005E+00 1.1215602612E+01 7.8651608433E+00 + 7.7071413220E+00 1.1564720398E+01 1.1550133754E+01 + 1.1489551803E+01 1.1416599349E+01 7.6960714288E+00 +:V(Bohr/atu): + -8.1840295684E-05 5.3557961387E-04 3.1333608552E-04 + 9.8623441709E-05 -3.9100363917E-05 3.5053215788E-04 + 4.1022447578E-04 -2.5475191415E-04 -2.8211133261E-04 + -1.9759200566E-04 -3.8052793102E-05 -2.7728583575E-04 + 2.0731623812E-04 3.0909724632E-04 -3.2705944612E-05 + -1.4858209482E-04 3.1421157397E-04 -4.0801148635E-05 + -5.3306375174E-04 -3.6087280890E-04 2.1510299849E-04 + 1.3363111298E-05 1.3428992892E-04 2.6110305485E-04 + 1.7201825354E-04 -2.7633876987E-04 7.5658225996E-05 + -2.5242864574E-04 4.7435305692E-05 -3.8605263831E-04 + 2.4589141501E-05 6.5441903308E-05 -2.5066329299E-04 + 9.6958788229E-05 -2.6827972192E-04 3.2794059764E-04 + 4.0372999156E-04 3.0838116161E-05 2.7513101855E-04 + 5.1833675821E-04 2.6899509800E-04 -5.2592766889E-05 + -4.8716739345E-04 4.3745406914E-04 -1.9496767625E-04 + 1.0922055901E-05 -5.7542911595E-04 -3.7638336700E-05 + 1.3219007924E-04 1.1838047740E-04 1.3345063824E-04 + -1.7069219112E-04 3.9571065816E-05 4.1367746925E-05 + 2.3830015544E-04 -2.8414687194E-04 -6.1367814997E-04 + -2.3051411764E-04 -2.5867934991E-05 -2.2242907240E-04 + 8.1381846364E-05 -1.3200255304E-04 9.5658158189E-05 + -3.1928891154E-04 5.8179388201E-05 1.0057888078E-05 + 2.4527861776E-04 2.4225219441E-04 -3.6569179023E-05 + -7.0619270538E-04 -4.8191619932E-06 1.3282060399E-04 + 2.0353073073E-04 -1.7809740755E-04 -4.0292186923E-04 + -4.8996809038E-05 -1.9747293738E-04 4.3193028981E-04 + 3.6532923875E-04 -9.1577812333E-05 1.5165910662E-05 + -2.1653611364E-04 1.7229506770E-04 2.0927191797E-04 + 2.0823119781E-05 1.3336523194E-05 -5.0072734713E-05 + -2.5440306043E-04 -3.8232987308E-04 -4.7468675021E-04 + 2.8502151312E-04 3.1246831316E-04 2.3008009146E-04 + 1.2939553871E-04 2.2300203995E-05 2.4694133862E-04 +:Pm_ion: + -6.1071292699E+01 3.9966301550E+02 2.3381928953E+02 + 7.3595299543E+01 -2.9177677689E+01 2.6157593683E+02 + 3.0611984992E+02 -1.9010230333E+02 -2.1051859141E+02 + -1.4744813801E+02 -2.8395953926E+01 -2.0691768394E+02 + 1.5470460552E+02 2.3065616081E+02 -2.4406000732E+01 + -1.1087570648E+02 2.3447260109E+02 -3.0446846140E+01 + -3.9778561572E+02 -2.6929239142E+02 1.6051528249E+02 + 9.9718906760E+00 1.0021053183E+02 1.9484168470E+02 + 1.2836435919E+02 -2.0621095950E+02 5.6458076382E+01 + -1.8836862185E+02 3.5397421453E+01 -2.8808221518E+02 + 1.8349037540E+01 4.8834398731E+01 -1.8705127110E+02 + 7.2353093133E+01 -2.0019709466E+02 2.4471754481E+02 + 3.0127350200E+02 2.3012180034E+01 2.0530970501E+02 + 3.8679596173E+02 2.0073092634E+02 -3.9246049072E+01 + -3.6353659563E+02 3.2643925924E+02 -1.4548979722E+02 + 8.1503135739E+00 -4.2939971898E+02 -2.8086676106E+01 + 1.0267778810E+02 9.1951269285E+01 1.0365691914E+02 + -1.3258405419E+02 3.0736569143E+01 3.2132129561E+01 + 1.8509810270E+02 -2.2070924288E+02 -4.7667052932E+02 + -1.7905034826E+02 -2.0092751005E+01 -1.7277034172E+02 + 6.3212822202E+01 -1.0253212833E+02 7.4301854971E+01 + -2.4800559459E+02 4.5190463064E+01 7.8123994380E+00 + 1.9051857812E+02 1.8816782338E+02 -2.8404873014E+01 + -5.4853061119E+02 -3.7432528734E+00 1.0316754411E+02 + 1.5809117720E+02 -1.3833600811E+02 -3.1296695293E+02 + -3.8057954158E+01 -1.5338582544E+02 3.3549905579E+02 + 2.8376712063E+02 -7.1132472748E+01 1.1780022905E+01 + -1.6819302417E+02 1.3382907819E+02 1.6255060721E+02 + 1.6174223457E+01 1.0359058035E+01 -3.8893672459E+01 + -1.9760592989E+02 -2.9697225327E+02 -3.6870985955E+02 + 2.2138861475E+02 2.4270773896E+02 1.7871322123E+02 + 1.0050714683E+02 1.7321539056E+01 1.9181008579E+02 +:NPH_BMASS: 0.1 +:NPH_INIT_Hamiltonian: -103.682126496114 +:KE: 0.166864193206538 +:Kbaro: 0.0169638070682247 +:Ubaro: 0 +:kinetic_stress: + 0.000277129724646706 -9.32366189484997e-07 4.02759588124573e-06 + -9.32366189484997e-07 0.000212585376793847 4.59478021839316e-05 + 4.02759588124573e-06 4.59478021839316e-05 0.000233457921300007 +:Pm_metric_tensor: + 0.519145325719798 0.000980646676623254 -0.00372936973493956 + 0.000980646676623254 0.502308511140885 0.000421349437850294 + -0.00372936973493956 0.000421349437850294 0.516335053920347 +:LATVEC_SCALE: 1.5208200323E+01 1.5208200323E+01 1.5208200323E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:INITIAL_ANGLES: 9.0000000000E+01 9.0000000000E+01 9.0000000000E+01 +:ROTATION_MATRIX: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:TTHRMI(K): 1120 +:EXTERNAL_PRESSURE: 0 +:EXTERNAL_STRESS: 0 0 0 0 0 0 GPa +:TEL(K): 1.1200000000E+03 +:TIO(K): 1.1331515000E+03 diff --git a/tests/Al16Si16_NPH_restart/high_accuracy/Reports/Report-6294427.out b/tests/Al16Si16_NPH_restart/high_accuracy/Reports/Report-6294427.out new file mode 100644 index 00000000..7b22be20 --- /dev/null +++ b/tests/Al16Si16_NPH_restart/high_accuracy/Reports/Report-6294427.out @@ -0,0 +1,30 @@ +--------------------------------------- +Begin Slurm Prolog: Apr-06-2026 12:26:44 +Job ID: 6294427 +User ID: strivedi44 +Account: gts-phanish6 +Job name: SPARC_testsuite +Partition: cpu-small +QOS: embers +--------------------------------------- + +Lmod is automatically replacing "gcc/12.3.0" with +"intel-oneapi-compilers/2023.1.0". + + +Inactive Modules: + 1) libpciaccess/0.17 2) mvapich2 3) pmix/4.2.6 4) slurm/23.11.1 + +/storage/scratch1/5/strivedi44/MD11/SPARC/tests/Al16Si16_NPH_restart/high_accuracy +--------------------------------------- +Begin Slurm Epilog: Apr-06-2026 12:32:29 +Job ID: 6294427 +User ID: strivedi44 +Account: gts-phanish6 +Job name: SPARC_testsuite +Resources: cpu=36,mem=72G,node=3 +Rsrc Used: cput=03:27:00,vmem=0,walltime=00:05:45,mem=12616K,energy_used=0 +Partition: cpu-small +QOS: embers +Nodes: atl1-1-02-015-5-2,atl1-1-02-015-11-1,atl1-1-02-015-26-2 +--------------------------------------- diff --git a/tests/Al16Si16_NPH_restart/high_accuracy/Reports/Report-6294460.out b/tests/Al16Si16_NPH_restart/high_accuracy/Reports/Report-6294460.out new file mode 100644 index 00000000..a847031e --- /dev/null +++ b/tests/Al16Si16_NPH_restart/high_accuracy/Reports/Report-6294460.out @@ -0,0 +1,30 @@ +--------------------------------------- +Begin Slurm Prolog: Apr-06-2026 12:34:10 +Job ID: 6294460 +User ID: strivedi44 +Account: gts-phanish6 +Job name: SPARC_testsuite +Partition: cpu-small +QOS: embers +--------------------------------------- + +Lmod is automatically replacing "gcc/12.3.0" with +"intel-oneapi-compilers/2023.1.0". + + +Inactive Modules: + 1) libpciaccess/0.17 2) mvapich2 3) pmix/4.2.6 4) slurm/23.11.1 + +/storage/scratch1/5/strivedi44/MD11/SPARC/tests/Al16Si16_NPH_restart/high_accuracy +--------------------------------------- +Begin Slurm Epilog: Apr-06-2026 12:37:31 +Job ID: 6294460 +User ID: strivedi44 +Account: gts-phanish6 +Job name: SPARC_testsuite +Resources: cpu=36,mem=72G,node=3 +Rsrc Used: cput=02:01:12,vmem=0,walltime=00:03:22,mem=12632K,energy_used=0 +Partition: cpu-small +QOS: embers +Nodes: atl1-1-02-020-18-2,atl1-1-02-020-31-[1-2] +--------------------------------------- diff --git a/tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.inpt b/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.inpt similarity index 72% rename from tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.inpt rename to tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.inpt index 3499e483..a75a793e 100644 --- a/tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.inpt +++ b/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.inpt @@ -1,14 +1,15 @@ -# nprocs: 48 -LATVEC_SCALE: 13.322568219 17.479965394 13.020212061 +# nprocs: 24 +LATVEC_SCALE: 15 15 15 LATVEC: 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 -MESH_SPACING: 0.30 +MESH_SPACING: 0.25 BC: P P P KPOINT_GRID: 1 1 1 +# SPIN_TYP: 1 EXCHANGE_CORRELATION: GGA_PBE -TOL_SCF: 1e-6 +TOL_SCF: 5e-7 # TOL_POISSON: 1e-7 # TOL_PSEUDOCHARGE: 1e-5 MIXING_PARAMETER: 1.0 @@ -18,21 +19,21 @@ PRECOND_KERKER_THRESH: 0 # MD MD_FLAG: 1 # 1 = MD, 0 = no MD (default) -ION_TEMP: 2400 # kelvin +ION_TEMP: 1120 # kelvin # ION_TEMP_END: 1120 -MD_METHOD: NPT_NP # NVE, NVT_NH (Nose-Hoover), NVK_G (Gaussian) +MD_METHOD: NPH # NVE, NVT_NH (Nose-Hoover), NVK_G (Gaussian) #QMASS: 1600 # mass for NH thermostat -MD_TIMESTEP: 1 # fs +MD_TIMESTEP: 0.6 # fs MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whichever comes first #TWTIME: 1400 RESTART_FLAG: 1 # 1 = restart MD from .restart file if present, 0 = start new #ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) -TARGET_PRESSURE: 0.1 GPa -NPT_NP_QMASS: 20000 -NPT_NP_BMASS: 1000 -NPT_SCALE_VECS: 3 +EXTERNAL_PRESSURE: 0 GPa +#NPT_NP_QMASS: 500.0 +NPH_BMASS: 0.1 +NPH_SCALE_CONSTRAINTS: 123 -NSTATES: 72 +NSTATES: 76 # outputs # CALC_PRES: 1 diff --git a/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.ion b/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.ion new file mode 100644 index 00000000..79360080 --- /dev/null +++ b/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.ion @@ -0,0 +1,53 @@ +#CELL: 15 15 15 +#LATVEC +# 1.000000000000000 0.000000000000000 0.000000000000000 +# 0.000000000000000 1.000000000000000 0.000000000000000 +# 0.100000000000000 0.100000000000000 0.900000000000000 +#PBC: True True True +# + + +ATOM_TYPE: Al # atom type followed with valence charge +N_TYPE_ATOM: 16 # number of atoms of this type +PSEUDO_POT: ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +ATOMIC_MASS: 26.9815385 +COORD: # coordinates follows +0.4 0 0 +3.75 0 3.75 +7.5 0 0.3 +11.25 0 3.75 +0 7.5 0 +3.75 7.5 3.75 +7.5 7.5 0 +11.25 7.5 3.75 +0.4 0 7.5 +3.75 0 11.25 +7.5 0 7.8 +11.25 0 11.25 +0 7.5 7.5 +3.75 7.5 11.25 +7.5 7.5 7.5 +11.25 7.5 11.25 + + +ATOM_TYPE: Si # atom type followed with valence charge +N_TYPE_ATOM: 16 # number of atoms of this type +PSEUDO_POT: ../../../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 +ATOMIC_MASS: 28.085 +COORD: # coordinates follows +0 3.75 3.75 +3.75 3.75 0 +7.5 3.75 3.75 +11.25 3.75 0 +0.3 11.25 3.75 +3.75 11.25 0.5 +7.5 11.25 3.75 +11.25 11.25 0 +0 3.75 11.25 +3.75 3.75 7.5 +7.5 3.75 11.25 +11.25 3.75 7.5 +0.3 11.25 11.25 +3.75 11.25 8 +7.5 11.25 11.25 +11.25 11.25 7.5 diff --git a/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.refaimd b/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.refaimd new file mode 100644 index 00000000..1c2ef550 --- /dev/null +++ b/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.refaimd @@ -0,0 +1,1517 @@ +:Description: + +:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr +:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu + where atu is the atomic unit of time, hbar/Ha +:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr +:Desc_MDTM: MD time. Unit=second +:Desc_TEL: Electronic temperature. Unit=Kelvin +:Desc_TIO: Ionic temperature. Unit=Kelvin +:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom +:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom +:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom + where N = number of particles, k = Boltzmann constant +:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom +:Desc_UEN: Internal energy. Unit=Ha/atom +:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom +:Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree +:Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 +:Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 +:Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during NPH ensemble (has same magnitude as initial LatVec). Unit = Bohr +:Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha +:Desc_NPH_Enthalpy: Enthalpy of the NPH system (or generalized enthalpy in case of anisotropic stress). This quantity is same as NPH Hamiltonian (NPH_HAMIL) plus the initial NPH hamiltonian. Unit = Ha +:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa +:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa +:Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa +:Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa +:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa + where N = number of particles, k = Boltzmann constant, V = volume +:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr + + + + +:MDSTEP: 21 +:MDTM: 15.42 +:TWIST: 0 +:TEL: 1120 +:TIO: 1132.43572080499 +:TEN: -3.2406230237E+00 +:KEN: 5.2112121844E-03 +:KENIG: 5.3793158033E-03 +:FEN: -3.2458342358E+00 +:UEN: -3.2449047214E+00 +:TSEN: -9.2951442336E-04 +:NPH_HAMIL: -8.1245441135E-04 +:NPH_ENTHALPY: -1.0368233921E+02 +:R: + 3.7823458916E-01 2.7610460926E-01 1.5878927437E-01 + 3.8306033205E+00 1.5184573827E+01 3.9859739488E+00 + 7.8281895558E+00 1.5074962428E+01 1.7561114565E-01 + 1.1293120965E+01 1.5189314181E+01 3.6481833123E+00 + 1.0435468268E-01 7.7713558143E+00 1.5192718538E+01 + 3.7321459897E+00 7.7627920119E+00 3.7783484433E+00 + 7.3190025969E+00 7.4168484355E+00 1.0284005934E-01 + 1.1415067004E+01 7.6738853814E+00 3.9386418353E+00 + 5.3229704039E-01 1.5066232122E+01 7.6519055296E+00 + 3.6530720897E+00 2.2840542397E-02 1.1191061767E+01 + 7.6121710804E+00 3.4847066886E-02 7.7850414043E+00 + 1.1445811536E+01 1.5068855172E+01 1.1568537402E+01 + 2.0175776191E-01 7.6157878874E+00 7.7412657720E+00 + 4.0760847909E+00 7.7499371772E+00 1.1381601394E+01 + 7.3492754612E+00 7.8332359584E+00 7.5012957501E+00 + 1.1418435117E+01 7.3193800096E+00 1.1383498648E+01 + 5.8236045647E-02 3.8678818278E+00 3.8703400677E+00 + 3.7226155939E+00 3.8210906346E+00 1.5203447282E+01 + 7.7130823852E+00 3.6601846015E+00 3.5222899517E+00 + 1.1317786229E+01 3.7738445375E+00 1.5096979981E+01 + 3.0428421164E-01 1.1342899268E+01 3.8577699134E+00 + 3.6493300723E+00 1.1438546793E+01 4.8043339327E-01 + 7.7087007769E+00 1.1530410366E+01 3.8252851649E+00 + 1.1099726003E+01 1.1393437716E+01 4.2518679669E-02 + 9.5144068216E-02 3.7066129992E+00 1.1222956160E+01 + 3.7963159924E+00 3.7030104254E+00 7.7924390927E+00 + 7.7618077996E+00 3.7504561440E+00 1.1424674305E+01 + 1.1301118907E+01 3.8912491122E+00 7.6990941122E+00 + 2.8980766672E-01 1.1408578417E+01 1.1414388909E+01 + 3.7181576669E+00 1.1215586629E+01 7.8651423642E+00 + 7.7071115916E+00 1.1564668770E+01 1.1550084397E+01 + 1.1489511031E+01 1.1416565408E+01 7.6960563643E+00 +:V: + -8.2421793773E-05 5.3324137256E-04 3.1237255288E-04 + 1.0082148503E-04 -3.8781097962E-05 3.4849424648E-04 + 4.0612528270E-04 -2.5341042609E-04 -2.8304891688E-04 + -1.9516226738E-04 -3.8237775806E-05 -2.7470564883E-04 + 2.0647395467E-04 3.0679796824E-04 -3.2754784855E-05 + -1.4897293233E-04 3.1369139688E-04 -4.0327799104E-05 + -5.2942846448E-04 -3.5904372369E-04 2.1482655800E-04 + 1.3320654644E-05 1.3401388898E-04 2.5996771242E-04 + 1.6656191448E-04 -2.7549506894E-04 7.3616272386E-05 + -2.4881417813E-04 4.6911608434E-05 -3.8184751283E-04 + 2.4972923869E-05 6.5100333487E-05 -2.4980473041E-04 + 9.8070582509E-05 -2.6740268412E-04 3.2704186527E-04 + 4.0242088890E-04 3.1360511143E-05 2.7461843356E-04 + 5.1559610080E-04 2.6700905675E-04 -5.2253138457E-05 + -4.8425180291E-04 4.3518564522E-04 -1.9438210396E-04 + 1.0239582043E-05 -5.7439787781E-04 -3.6924756597E-05 + 1.3360597087E-04 1.1741657923E-04 1.3273605820E-04 + -1.7131562488E-04 3.9528882944E-05 4.3993417105E-05 + 2.3842593280E-04 -2.8400816396E-04 -6.1569277695E-04 + -2.3365563042E-04 -2.3450584186E-05 -2.2160032713E-04 + 8.6111484207E-05 -1.3222221478E-04 9.5576469180E-05 + -3.1879797928E-04 5.7949657339E-05 1.3647399370E-05 + 2.4596507876E-04 2.4134021510E-04 -4.0613571409E-05 + -7.0987483582E-04 -3.8445006400E-06 1.3419711866E-04 + 2.0386174646E-04 -1.7682917905E-04 -4.0474945914E-04 + -5.1474229644E-05 -1.9722458927E-04 4.3355887188E-04 + 3.6767032290E-04 -9.0749947295E-05 1.4072839721E-05 + -2.1643377724E-04 1.7136339796E-04 2.1098104317E-04 + 2.3281024073E-05 1.4153971192E-05 -5.3351780119E-05 + -2.5948600174E-04 -3.8107291689E-04 -4.7375797515E-04 + 2.8882841236E-04 3.1176032975E-04 2.2723739741E-04 + 1.2777682811E-04 2.2175836254E-05 2.4928450290E-04 +:F: + -3.3244377550E-03 -4.2992906905E-03 -1.0202028850E-03 + 1.0237388237E-02 8.6479944708E-04 -4.8694053010E-03 + -1.2203344484E-02 2.7430872352E-03 -6.1867527747E-03 + 7.4500492630E-03 -1.0544122299E-03 7.4905616820E-03 + -1.2298460554E-03 -6.0155589798E-03 -4.4115447892E-04 + -2.9972434497E-03 9.3824993905E-04 1.5431715026E-03 + 9.5197998952E-03 3.7648233179E-03 1.1585646839E-03 + -3.2866859475E-04 3.5240962324E-04 -1.8391527542E-03 + -2.0189367368E-02 6.3654434526E-04 -6.9288386285E-03 + 1.1775386995E-02 -1.5563123082E-03 1.2893467339E-02 + 1.5997057842E-03 -5.9694243054E-04 8.4448558442E-04 + 5.3089821577E-03 9.1255227804E-04 -4.0879281573E-04 + -1.4646643991E-03 2.3480036036E-03 6.2501528257E-04 + -6.3808498580E-03 -5.1124347509E-03 4.5420387970E-04 + 7.0945490743E-03 -4.9048176974E-03 1.8740934084E-04 + -2.4005254168E-03 -1.5125326328E-03 2.2764705855E-03 + 7.3048092253E-03 -2.7188583763E-03 -1.5375390608E-03 + -4.2935917794E-03 2.8898812081E-04 1.1184212485E-02 + 2.7893982816E-03 -2.3249599708E-03 -1.4239462005E-02 + -1.5490272913E-02 9.5471430361E-03 1.0174165029E-03 + 2.0420389399E-02 -2.4510186544E-03 6.8447566162E-04 + -1.1511465036E-03 -4.3492145790E-04 1.4824309188E-02 + 5.4145575326E-03 -1.2460563802E-03 -1.7030709979E-02 + -2.2216390219E-02 4.1408833109E-03 7.0753669534E-03 + 3.4290291481E-03 3.3641788403E-03 -1.1610374111E-02 + -1.0530105120E-02 -8.7965223299E-04 1.0980881814E-02 + 1.3393749443E-02 2.4934149122E-03 -4.3732955065E-03 + -1.7201754694E-03 -2.0043460901E-03 9.2630844966E-03 + 1.0467075118E-02 3.4802235242E-03 -1.3913210709E-02 + -2.3550765744E-02 1.2547573820E-03 -8.8535889193E-04 + 1.8598937862E-02 3.2729114913E-04 -9.2393095533E-03 + -5.3324122884E-03 -3.4523518221E-04 1.2020462474E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5174622645E+03 +:LATVEC_SCALE: + 1.5208153325E+01 1.5208153325E+01 1.5208153325E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 1.0711255155E+00 -2.3095050820E-03 1.2554602859E-02 + -2.3095050820E-03 8.1637717655E-01 1.7709301974E-01 + 1.2554602859E-02 1.7709301974E-01 9.0212949519E-01 +:STRESS: + -3.4858326460E+00 -3.1579174947E-01 1.2139582116E+00 + -3.1579174947E-01 1.3147539599E+00 4.4203528391E-02 + 1.2139582116E+00 4.4203528391E-02 -2.7268825305E+00 +:CONSTRESS: + 4.0304888349E+00 6.1737540405E-01 -2.3590572596E+00 + 6.1737540405E-01 -6.2600732105E+00 2.6467661268E-01 + -2.3590572596E+00 2.6467661268E-01 2.2295843756E+00 +:TOTSTRESS: + 5.2646932660E-01 -3.0389315966E-01 1.1576536509E+00 + -3.0389315966E-01 5.7616964272E+00 -1.3178712133E-01 + 1.1576536509E+00 -1.3178712133E-01 1.3994276500E+00 +:PRESIO: 9.2987739574E-01 +:PRES: 1.6326537389E+00 +:CONPRES: -6.9245956164E-14 +:TOTPRES: 2.5625311346E+00 +:PRESIG: 9.5987344077E-01 +:MIND: +Al - Al: 4.7214415398E+00 +Si - Si: 4.7544591942E+00 +Al - Si: 4.8763245322E+00 + + +:MDSTEP: 22 +:MDTM: 6.80 +:TWIST: 0 +:TEL: 1120 +:TIO: 1134.0128938427 +:TEN: -3.2406570192E+00 +:KEN: 5.2184699768E-03 +:KENIG: 5.3868077180E-03 +:FEN: -3.2458754892E+00 +:UEN: -3.2449671108E+00 +:TSEN: -9.0837840439E-04 +:NPH_HAMIL: -8.1570659121E-04 +:NPH_ENTHALPY: -1.0368234246E+02 +:R: + 3.7663024054E-01 2.8965914825E-01 1.6673528256E-01 + 3.8378648203E+00 1.5202221077E+01 3.9994822176E+00 + 7.8477908679E+00 1.5087156773E+01 1.6875798848E-01 + 1.1302157674E+01 1.5206968713E+01 3.6458778016E+00 + 1.0960266716E-01 7.7884594263E+00 1.5210517253E+01 + 3.7330002740E+00 7.7800998790E+00 3.7819859971E+00 + 7.3148813868E+00 7.4170426128E+00 1.0830858413E-01 + 1.1429382132E+01 7.6866183167E+00 3.9499125115E+00 + 5.3695940524E-01 1.5077854101E+01 7.6630659473E+00 + 3.6514424229E+00 2.4023841423E-02 1.1195371148E+01 + 7.6221281551E+00 3.6502805930E-02 7.7883813972E+00 + 1.1462304422E+01 1.5080683069E+01 1.1590831403E+01 + 2.1199000390E-01 7.6259127170E+00 7.7575749169E+00 + 4.0938440137E+00 7.7660320355E+00 1.1394251881E+01 + 7.3462981271E+00 7.8536108810E+00 7.5056604003E+00 + 1.1432664878E+01 7.3140733469E+00 1.1396543556E+01 + 6.1669481758E-02 3.8755206766E+00 3.8783694984E+00 + 3.7228962535E+00 3.8267558910E+00 1.5223235253E+01 + 7.7284710177E+00 3.6576018679E+00 3.5112291200E+00 + 1.1325757316E+01 3.7779434979E+00 1.5109980256E+01 + 3.0691849268E-01 1.1353498695E+01 3.8648744446E+00 + 3.6458770887E+00 1.1453998502E+01 4.8145017224E-01 + 7.7242870713E+00 1.1550524295E+01 3.8288610026E+00 + 1.1095562436E+01 1.1407327014E+01 4.5946158861E-02 + 1.0034422504E-01 3.7067831938E+00 1.1226585247E+01 + 3.7996257192E+00 3.7026441488E+00 7.8128204097E+00 + 7.7805297460E+00 3.7528126151E+00 1.1438995632E+01 + 1.1309580127E+01 3.9002606716E+00 7.7138229543E+00 + 2.9080391873E-01 1.1422929287E+01 1.1426965732E+01 + 3.7161272745E+00 1.1219872100E+01 7.8630079586E+00 + 7.7238397820E+00 1.1586583039E+01 1.1569824095E+01 + 1.1506729892E+01 1.1431102273E+01 7.7117493487E+00 +:V: + -8.3917971184E-05 5.3036881764E-04 3.1145945871E-04 + 1.0589315206E-04 -3.8325467987E-05 3.4556339577E-04 + 3.9929086064E-04 -2.5166224294E-04 -2.8584024555E-04 + -1.9109340523E-04 -3.8739004989E-05 -2.7052533903E-04 + 2.0556975939E-04 3.0337039900E-04 -3.2933207417E-05 + -1.5032946427E-04 3.1380795439E-04 -3.9525230901E-05 + -5.2392765941E-04 -3.5666683397E-04 2.1509718609E-04 + 1.3171187854E-05 1.3406782939E-04 2.5875987959E-04 + 1.5605782334E-04 -2.7486878249E-04 6.9941048636E-05 + -2.4247179812E-04 4.5986861641E-05 -3.7471381678E-04 + 2.5740199697E-05 6.4759957813E-05 -2.4899510095E-04 + 1.0069974324E-04 -2.6664453173E-04 3.2636689267E-04 + 4.0108881742E-04 3.2516686470E-05 2.7459083216E-04 + 5.1175154738E-04 2.6408604007E-04 -5.1891477730E-05 + -4.7995939669E-04 4.3212661903E-04 -1.9411744889E-04 + 9.0595802463E-06 -5.7442325211E-04 -3.5716419988E-05 + 1.3709784325E-04 1.1598460136E-04 1.3178293140E-04 + -1.7323738469E-04 3.9636523217E-05 4.9353127090E-05 + 2.3940996184E-04 -2.8485703215E-04 -6.2182296454E-04 + -2.4095899869E-04 -1.8722838838E-05 -2.2081841199E-04 + 9.5925595274E-05 -1.3328258947E-04 9.5862660380E-05 + -3.1889900558E-04 5.7698792362E-05 2.0842805040E-05 + 2.4817375250E-04 2.4042342457E-04 -4.8768623135E-05 + -7.1967471854E-04 -1.8973341020E-06 1.3737607120E-04 + 2.0522255090E-04 -1.7496119402E-04 -4.0991782666E-04 + -5.6530984639E-05 -1.9741169283E-04 4.3823000061E-04 + 3.7374805341E-04 -8.9454021768E-05 1.1951703857E-05 + -2.1701255256E-04 1.7013592676E-04 2.1532541552E-04 + 2.8289667958E-05 1.5889309204E-05 -5.9993231086E-05 + -2.7067216080E-04 -3.7989421391E-04 -4.7369105216E-04 + 2.9745194736E-04 3.1156562314E-04 2.2254213002E-04 + 1.2512619030E-04 2.1949099955E-05 2.5473575246E-04 +:F: + -3.0130297617E-03 -4.5098327112E-03 -1.0861484941E-03 + 1.0377179056E-02 7.5494715878E-04 -5.0681878240E-03 + -1.2943958369E-02 2.9632374742E-03 -6.2640628911E-03 + 7.7478508315E-03 -1.1201763902E-03 7.7633283205E-03 + -1.3554032593E-03 -6.0956314270E-03 -4.2591782771E-04 + -3.1090069874E-03 1.0474929470E-03 1.4457545034E-03 + 9.7370871443E-03 3.9233737200E-03 9.5865011463E-04 + -1.9982928210E-04 5.1231032645E-04 -1.6913716566E-03 + -2.0683156239E-02 5.1091056263E-04 -7.2972383914E-03 + 1.2183536909E-02 -1.8852027107E-03 1.3559334474E-02 + 1.5662382046E-03 -4.3768284959E-04 1.1549851465E-03 + 5.5999386107E-03 7.9745487212E-04 -6.8129893074E-04 + -1.8667627354E-03 2.3921170151E-03 5.9902898565E-04 + -6.3711158644E-03 -5.1898404568E-03 7.2700516573E-04 + 7.5864587425E-03 -5.1204070372E-03 -8.0982594656E-05 + -2.2322607240E-03 -1.3775301417E-03 2.3390266848E-03 + 7.7931183723E-03 -2.6023860826E-03 -1.7282272220E-03 + -4.5098864472E-03 3.5537435636E-04 1.1176014829E-02 + 2.4803971537E-03 -2.6165977239E-03 -1.4192909560E-02 + -1.5856520801E-02 9.8617034149E-03 1.0920693820E-03 + 2.0551190110E-02 -2.5970179971E-03 9.8053590666E-04 + -8.7770560472E-04 -3.0841997633E-04 1.4964633275E-02 + 4.9517363544E-03 -1.3207437640E-03 -1.6858468748E-02 + -2.1849613608E-02 3.8824575959E-03 6.7335666348E-03 + 3.2222353416E-03 3.4575214370E-03 -1.1782903734E-02 + -1.0616545654E-02 -8.9005361490E-04 1.0504609025E-02 + 1.3568157053E-02 2.4006515248E-03 -4.3167877189E-03 + -1.7643737212E-03 -2.1993284785E-03 9.7471303066E-03 + 1.0338482200E-02 3.7588233480E-03 -1.3788519233E-02 + -2.3964117808E-02 1.6873359006E-03 -1.2326764510E-03 + 1.8479873372E-02 4.4424816357E-04 -9.0056593550E-03 + -4.9701925893E-03 -4.7910845575E-04 1.1755687878E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5304074746E+03 +:LATVEC_SCALE: + 1.5226787187E+01 1.5226787187E+01 1.5226787187E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0728761471E+00 2.2120811508E-04 6.7483672593E-03 + 2.2120811508E-04 8.0716288104E-01 1.7634252690E-01 + 6.7483672593E-03 1.7634252690E-01 9.0323515336E-01 +:STRESS: + -3.2401879380E+00 -3.2162246550E-01 1.2439907849E+00 + -3.2162246550E-01 1.3487115264E+00 4.2489028460E-02 + 1.2439907849E+00 4.2489028460E-02 -2.4271015366E+00 +:CONSTRESS: + 3.9287532800E+00 6.3336366193E-01 -2.4312964226E+00 + 6.3336366193E-01 -5.9516610137E+00 2.6677411927E-01 + -2.4312964226E+00 2.6677411927E-01 2.0229077336E+00 +:TOTSTRESS: + 3.8431080510E-01 -3.1151998831E-01 1.1940540049E+00 + -3.1151998831E-01 5.4101123683E+00 -1.3292062084E-01 + 1.1940540049E+00 -1.3292062084E-01 1.3074289563E+00 +:PRESIO: 9.2775806051E-01 +:PRES: 1.4395259827E+00 +:CONPRES: -8.0676190770E-14 +:TOTPRES: 2.3672840432E+00 +:PRESIG: 9.5768573989E-01 +:MIND: +Al - Al: 4.7124408323E+00 +Si - Si: 4.7546087667E+00 +Al - Si: 4.8721193883E+00 + + +:MDSTEP: 23 +:MDTM: 6.74 +:TWIST: 0 +:TEL: 1120 +:TIO: 1135.65054686746 +:TEN: -3.2406891457E+00 +:KEN: 5.2260060844E-03 +:KENIG: 5.3945869258E-03 +:FEN: -3.2459151518E+00 +:UEN: -3.2450270624E+00 +:TSEN: -8.8808938446E-04 +:NPH_HAMIL: -8.1702242112E-04 +:NPH_ENTHALPY: -1.0368234378E+02 +:R: + 3.7500014445E-01 3.0316687323E-01 1.7467325892E-01 + 3.8453792145E+00 1.5220364330E+01 4.0130552790E+00 + 7.8674815404E+00 1.5099870936E+01 1.6183155793E-01 + 1.1311653028E+01 1.5225095914E+01 3.6437860165E+00 + 1.1483733857E-01 7.8057362035E+00 1.5228797451E+01 + 3.7339349856E+00 7.7976701206E+00 3.7857626790E+00 + 7.3111158657E+00 7.4175230578E+00 1.1379274558E-01 + 1.1444060586E+01 7.6996037951E+00 3.9612886233E+00 + 5.4138001438E-01 1.5089964867E+01 7.6743802898E+00 + 3.6500820451E+00 2.5184331679E-02 1.1200208408E+01 + 7.6323488276E+00 3.8154280267E-02 7.7919849502E+00 + 1.1479234398E+01 1.5093003440E+01 1.1613488103E+01 + 2.2220595302E-01 7.6363116148E+00 7.7741400685E+00 + 4.1116548557E+00 7.7823106566E+00 1.1407276130E+01 + 7.3436505838E+00 7.8741733665E+00 7.5102641223E+00 + 1.1447232610E+01 7.3089830966E+00 1.1409982501E+01 + 6.5198770548E-02 3.8832523420E+00 3.8865023676E+00 + 3.7232416728E+00 3.8325479363E+00 1.5243644992E+01 + 7.7441370427E+00 3.6551045015E+00 3.5001094172E+00 + 1.1333899920E+01 3.7822820309E+00 1.5123477129E+01 + 3.0980996359E-01 1.1364430162E+01 3.8721145500E+00 + 3.6425299955E+00 1.1469813151E+01 4.8266244708E-01 + 7.7401803686E+00 1.1570992211E+01 3.8323564944E+00 + 1.1091490542E+01 1.1421628141E+01 4.9456238034E-02 + 1.0558652223E-01 3.7071135033E+00 1.1230431567E+01 + 3.8029292679E+00 3.7023855229E+00 7.8335785253E+00 + 7.7996642724E+00 3.7553180216E+00 1.1453631150E+01 + 1.1318381938E+01 3.9093707304E+00 7.7289161429E+00 + 2.9193390349E-01 1.1437691012E+01 1.1439742333E+01 + 3.7139272572E+00 1.1224536702E+01 7.8611100324E+00 + 7.7410377833E+00 1.1608873741E+01 1.1589825910E+01 + 1.1524257336E+01 1.1445999265E+01 7.7278308121E+00 +:V: + -8.5255061997E-05 5.2738110546E-04 3.1050598689E-04 + 1.1102094885E-04 -3.7924411631E-05 3.4252881519E-04 + 3.9207956882E-04 -2.4979099610E-04 -2.8865754596E-04 + -1.8687435117E-04 -3.9268964779E-05 -2.6620412373E-04 + 2.0460073516E-04 2.9990159236E-04 -3.3102858944E-05 + -1.5173374640E-04 3.1396668709E-04 -3.8776592832E-05 + -5.1831547123E-04 -3.5420565661E-04 2.1525836308E-04 + 1.3087822297E-05 1.3419684516E-04 2.5762506524E-04 + 1.4531747434E-04 -2.7430093259E-04 6.6086134880E-05 + -2.3592666317E-04 4.4894830508E-05 -3.6724283182E-04 + 2.6489597855E-05 6.4502073741E-05 -2.4802321175E-04 + 1.0347127772E-04 -2.6593694802E-04 3.2554439134E-04 + 3.9954114177E-04 3.3688804475E-05 2.7454093900E-04 + 5.0790834887E-04 2.6112322372E-04 -5.1388151227E-05 + -4.7541112896E-04 4.2894951459E-04 -1.9398310293E-04 + 7.9686016485E-06 -5.7436081828E-04 -3.4478539520E-05 + 1.4081347008E-04 1.1461057410E-04 1.3073384187E-04 + -1.7525788336E-04 3.9777468855E-05 5.4697723289E-05 + 2.4024116635E-04 -2.8583641165E-04 -6.2789706666E-04 + -2.4841955523E-04 -1.3854240866E-05 -2.1999677784E-04 + 1.0577641765E-04 -1.3440649389E-04 9.6280213661E-05 + -3.1886202409E-04 5.7507224093E-05 2.8093247193E-05 + 2.5014857108E-04 2.3946311903E-04 -5.6825798197E-05 + -7.2924575884E-04 -8.5819523832E-08 1.4038848412E-04 + 2.0647016446E-04 -1.7304700952E-04 -4.1514005232E-04 + -6.1613249994E-05 -1.9759364806E-04 4.4264490572E-04 + 3.7988546322E-04 -8.8206906406E-05 9.8607578764E-06 + -2.1760821930E-04 1.6880951626E-04 2.1987897717E-04 + 3.3228742079E-05 1.7757906273E-05 -6.6561636713E-05 + -2.8202663414E-04 -3.7849299631E-04 -4.7376841081E-04 + 3.0598670019E-04 3.1141613850E-04 2.1795222730E-04 + 1.2264915814E-04 2.1656189268E-05 2.6004408949E-04 +:F: + -2.7106460828E-03 -4.7062990610E-03 -1.1472856806E-03 + 1.0497862039E-02 6.4585090854E-04 -5.2536846342E-03 + -1.3684179652E-02 3.2095937588E-03 -6.3380771702E-03 + 8.0429510648E-03 -1.1755716540E-03 8.0375608021E-03 + -1.4667126529E-03 -6.1594000895E-03 -4.1120585053E-04 + -3.2115637876E-03 1.1441073194E-03 1.3283499904E-03 + 9.9255409103E-03 4.0678879959E-03 7.5157035341E-04 + -6.5514678010E-05 6.6678946651E-04 -1.5240869471E-03 + -2.1159673797E-02 3.7453093776E-04 -7.6515047828E-03 + 1.2581841403E-02 -2.2191108487E-03 1.4221682132E-02 + 1.5356449487E-03 -2.6345966748E-04 1.4622547092E-03 + 5.8990336013E-03 6.8339471999E-04 -9.5809111988E-04 + -2.2782958267E-03 2.4208896120E-03 5.6960394748E-04 + -6.3325561625E-03 -5.2528358055E-03 1.0118575234E-03 + 8.0729615874E-03 -5.3361959135E-03 -3.5183184115E-04 + -2.0519807482E-03 -1.2336349288E-03 2.3953343321E-03 + 8.2641398116E-03 -2.4722448725E-03 -1.9222090374E-03 + -4.7330470142E-03 4.3208401905E-04 1.1155428946E-02 + 2.1932979163E-03 -2.9042048556E-03 -1.4117402312E-02 + -1.6207222344E-02 1.0150782970E-02 1.1577076095E-03 + 2.0634341673E-02 -2.7356197540E-03 1.2406043058E-03 + -6.2172763461E-04 -1.8402473700E-04 1.5091087080E-02 + 4.4911455559E-03 -1.4002425343E-03 -1.6674309686E-02 + -2.1411879201E-02 3.5903263362E-03 6.4210116848E-03 + 2.9942885413E-03 3.5425623702E-03 -1.1910866340E-02 + -1.0668483770E-02 -8.8418430063E-04 1.0001601797E-02 + 1.3718377483E-02 2.2872005500E-03 -4.2579507455E-03 + -1.8201939466E-03 -2.3978905445E-03 1.0176479278E-02 + 1.0208910925E-02 4.0415200299E-03 -1.3653040248E-02 + -2.4337293086E-02 2.1320864893E-03 -1.5405674896E-03 + 1.8313799208E-02 5.5227455101E-04 -8.8001262934E-03 + -4.6131662850E-03 -6.1696246711E-04 1.1490105686E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5437242404E+03 +:LATVEC_SCALE: + 1.5245908411E+01 1.5245908411E+01 1.5245908411E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0746705002E+00 2.7918953401E-03 1.1372258639E-03 + 2.7918953401E-03 7.9781434755E-01 1.7561491852E-01 + 1.1372258639E-03 1.7561491852E-01 9.0433450463E-01 +:STRESS: + -2.9959074197E+00 -3.2790030283E-01 1.2731212218E+00 + -3.2790030283E-01 1.3910926408E+00 4.0917947456E-02 + 1.2731212218E+00 4.0917947456E-02 -2.1253504275E+00 +:CONSTRESS: + 3.8359415103E+00 6.5048830325E-01 -2.5015050399E+00 + 6.5048830325E-01 -5.6535624544E+00 2.6858013423E-01 + -2.5015050399E+00 2.6858013423E-01 1.8176209442E+00 +:TOTSTRESS: + 2.3463640963E-01 -3.1979610508E-01 1.2295210439E+00 + -3.1979610508E-01 5.0602841612E+00 -1.3388316317E-01 + 1.2295210439E+00 -1.3388316317E-01 1.2120639880E+00 +:PRESIO: 9.2560645080E-01 +:PRES: 1.2433884021E+00 +:CONPRES: -1.1523271400E-13 +:TOTPRES: 2.1689948529E+00 +:PRESIG: 9.5546472341E-01 +:MIND: +Al - Al: 4.7040726548E+00 +Si - Si: 4.7546307894E+00 +Al - Si: 4.8681165361E+00 + + +:MDSTEP: 24 +:MDTM: 5.94 +:TWIST: 0 +:TEL: 1120 +:TIO: 1137.34934125519 +:TEN: -3.2407191317E+00 +:KEN: 5.2338235506E-03 +:KENIG: 5.4026565684E-03 +:FEN: -3.2459529553E+00 +:UEN: -3.2450842301E+00 +:TSEN: -8.6872517950E-04 +:NPH_HAMIL: -8.1597918360E-04 +:NPH_ENTHALPY: -1.0368234273E+02 +:R: + 3.7334684034E-01 3.1662473819E-01 1.8260210609E-01 + 3.8531359410E+00 1.5238954068E+01 4.0266783624E+00 + 7.8872276984E+00 1.5113060083E+01 1.5483020613E-01 + 1.1321574830E+01 1.5243646922E+01 3.6418996855E+00 + 1.2005708470E-01 7.8231608773E+00 1.5247511140E+01 + 3.7349369238E+00 7.8154795163E+00 3.7896650218E+00 + 7.3076849136E+00 7.4182678775E+00 1.1928974405E-01 + 1.1459067874E+01 7.7128195027E+00 3.9727599239E+00 + 5.4555127979E-01 1.5102514804E+01 7.6858198979E+00 + 3.6489842426E+00 2.6317782132E-02 1.1205546176E+01 + 7.6428086021E+00 3.9803597229E-02 7.7958310988E+00 + 1.1496568991E+01 1.5105766943E+01 1.1636467550E+01 + 2.3240003576E-01 7.6469608219E+00 7.7909364739E+00 + 4.1295051581E+00 7.7987478286E+00 1.1420641605E+01 + 7.3413153712E+00 7.8948961182E+00 7.5150796392E+00 + 1.1462104382E+01 7.3040875413E+00 1.1423780090E+01 + 6.8829478276E-02 3.8910661921E+00 3.8947241448E+00 + 3.7236372667E+00 3.8384556043E+00 1.5264628098E+01 + 7.7600526923E+00 3.6526772797E+00 3.4889202303E+00 + 1.1342173801E+01 3.7868516515E+00 1.5137423416E+01 + 3.1295873149E-01 1.1375655971E+01 3.8794811851E+00 + 3.6392801284E+00 1.1485956011E+01 4.8407024120E-01 + 7.7563508342E+00 1.1591776740E+01 3.8357616898E+00 + 1.1087479987E+01 1.1436301472E+01 5.3045103280E-02 + 1.1086803179E-01 3.7075931082E+00 1.1234457771E+01 + 3.8062139400E+00 3.7022227708E+00 7.8546829390E+00 + 7.8191888033E+00 3.7579590631E+00 1.1468545359E+01 + 1.1327487723E+01 3.9185646577E+00 7.7443545687E+00 + 2.9319516784E-01 1.1452830845E+01 1.1452684119E+01 + 3.7115411684E+00 1.1229550026E+01 7.8594196867E+00 + 7.7586793489E+00 1.1631505692E+01 1.1610055820E+01 + 1.1542061306E+01 1.1461218548E+01 7.7442733161E+00 +:V: + -8.6438121984E-05 5.2428771534E-04 3.0951568344E-04 + 1.1619503338E-04 -3.7577572228E-05 3.3939852546E-04 + 3.8449389199E-04 -2.4778424728E-04 -2.9149970733E-04 + -1.8250792232E-04 -3.9822630784E-05 -2.6174290610E-04 + 2.0357480477E-04 2.9640080115E-04 -3.3264331723E-05 + -1.5318113869E-04 3.1416193265E-04 -3.8091488671E-05 + -5.1260829927E-04 -3.5166875224E-04 2.1530725130E-04 + 1.3073138993E-05 1.3439847047E-04 2.5657370623E-04 + 1.3435168597E-04 -2.7379761959E-04 6.2059658842E-05 + -2.2918557169E-04 4.3633587837E-05 -3.5943890890E-04 + 2.7222787807E-05 6.4333613289E-05 -2.4689209499E-04 + 1.0638897769E-04 -2.6528022852E-04 3.2457375774E-04 + 3.9777512214E-04 3.4868935314E-05 2.7446804677E-04 + 5.0408240969E-04 2.5812925041E-04 -5.0737890756E-05 + -4.7061259241E-04 4.2565647425E-04 -1.9398070810E-04 + 6.9724509253E-06 -5.7420779436E-04 -3.3214049748E-05 + 1.4474397896E-04 1.1330095940E-04 1.2958779279E-04 + -1.7738082049E-04 3.9956408130E-05 6.0020842358E-05 + 2.4093223676E-04 -2.8694465958E-04 -6.3390414037E-04 + -2.5603024003E-04 -8.8577122009E-06 -2.1913941679E-04 + 1.1564073191E-04 -1.3559029446E-04 9.6812613852E-05 + -3.1869671669E-04 5.7374154630E-05 3.5391193686E-05 + 2.5189227383E-04 2.3845785150E-04 -6.4778838230E-05 + -7.3855694840E-04 1.5741853207E-06 1.4324867262E-04 + 2.0759628796E-04 -1.7109125982E-04 -4.2039612173E-04 + -6.6705106973E-05 -1.9776300803E-04 4.4679311352E-04 + 3.8607130945E-04 -8.7018789738E-05 7.8014499801E-06 + -2.1822684369E-04 1.6738355360E-04 2.2461479597E-04 + 3.8098547100E-05 1.9761064653E-05 -7.3051755089E-05 + -2.9353003848E-04 -3.7686576473E-04 -4.7397215709E-04 + 3.1441074993E-04 3.1130812534E-04 2.1345531924E-04 + 1.2034351162E-04 2.1295478188E-05 2.6520963704E-04 +:F: + -2.4177163491E-03 -4.8873492658E-03 -1.2036166942E-03 + 1.0598641817E-02 5.3772911795E-04 -5.4263162438E-03 + -1.4423594973E-02 3.4833962954E-03 -6.4080237440E-03 + 8.3337404618E-03 -1.2211553493E-03 8.3119179586E-03 + -1.5640375196E-03 -6.2076699228E-03 -3.9788542240E-04 + -3.3035133110E-03 1.2270521212E-03 1.1932332643E-03 + 1.0086355374E-02 4.1980654708E-03 5.3709414436E-04 + 7.3706186512E-05 8.1556674422E-04 -1.3381386120E-03 + -2.1616122336E-02 2.2809393101E-04 -7.9903113555E-03 + 1.2968625983E-02 -2.5573209455E-03 1.4878488028E-02 + 1.5085451197E-03 -7.7178557126E-05 1.7649788673E-03 + 6.2050535329E-03 5.7049239106E-04 -1.2381470260E-03 + -2.6978911948E-03 2.4334539239E-03 5.3712331779E-04 + -6.2672009896E-03 -5.3002315839E-03 1.3070552848E-03 + 8.5511952252E-03 -5.5501892993E-03 -6.2483767535E-04 + -1.8605986837E-03 -1.0796847250E-03 2.4471301965E-03 + 8.7159676244E-03 -2.3306655661E-03 -2.1195350333E-03 + -4.9632597510E-03 5.1750540709E-04 1.1121439073E-02 + 1.9328766462E-03 -3.1861100907E-03 -1.4018357076E-02 + -1.6543590817E-02 1.0414077980E-02 1.2192481417E-03 + 2.0670406435E-02 -2.8653989184E-03 1.4679279182E-03 + -3.8324452617E-04 -6.1336385851E-05 1.5201980942E-02 + 4.0355294110E-03 -1.4846033668E-03 -1.6476916844E-02 + -2.0908322297E-02 3.2661416980E-03 6.1363187437E-03 + 2.7501409230E-03 3.6198093363E-03 -1.1996671929E-02 + -1.0689713340E-02 -8.6117411527E-04 9.4758369522E-03 + 1.3843024602E-02 2.1535980429E-03 -4.1959505413E-03 + -1.8867414706E-03 -2.5985237782E-03 1.0548509900E-02 + 1.0081957441E-02 4.3264072791E-03 -1.3507027153E-02 + -2.4670422031E-02 2.5857316227E-03 -1.8083372667E-03 + 1.8101684260E-02 6.4972974985E-04 -8.6210949493E-03 + -4.2614814537E-03 -7.5825924118E-04 1.1222884834E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5573814595E+03 +:LATVEC_SCALE: + 1.5265468793E+01 1.5265468793E+01 1.5265468793E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0765273713E+00 5.3938588914E-03 -4.2605734211E-03 + 5.3938588914E-03 7.8835479969E-01 1.7489834000E-01 + -4.2605734211E-03 1.7489834000E-01 9.0541447039E-01 +:STRESS: + -2.7541777066E+00 -3.3475636926E-01 1.3012099599E+00 + -3.3475636926E-01 1.4412747392E+00 3.9539421890E-02 + 1.3012099599E+00 3.9539421890E-02 -1.8237892644E+00 +:CONSTRESS: + 3.7519194220E+00 6.6871043255E-01 -2.5693777964E+00 + 6.6871043255E-01 -5.3672385543E+00 2.7008433520E-01 + -2.5693777964E+00 2.7008433520E-01 1.6153191323E+00 +:TOTSTRESS: + 7.8785655851E-02 -3.2856020440E-01 1.2639072630E+00 + -3.2856020440E-01 4.7143186148E+00 -1.3472541709E-01 + 1.2639072630E+00 -1.3472541709E-01 1.1138846025E+00 +:PRESIO: 9.2343221380E-01 +:PRES: 1.0455640772E+00 +:CONPRES: 1.7238388703E-13 +:TOTPRES: 1.9689962910E+00 +:PRESIG: 9.5322034973E-01 +:MIND: +Al - Al: 4.6963382574E+00 +Si - Si: 4.7545131835E+00 +Al - Si: 4.8642974675E+00 + + +:MDSTEP: 25 +:MDTM: 6.57 +:TWIST: 0 +:TEL: 1120 +:TIO: 1139.1109285504 +:TEN: -3.2407467733E+00 +:KEN: 5.2419299755E-03 +:KENIG: 5.4110244909E-03 +:FEN: -3.2459887033E+00 +:UEN: -3.2451383311E+00 +:TSEN: -8.5037216493E-04 +:NPH_HAMIL: -8.1314616850E-04 +:NPH_ENTHALPY: -1.0368233990E+02 +:R: + 3.7167276285E-01 3.3002980584E-01 1.9052073766E-01 + 3.8611241783E+00 1.5257940813E+01 4.0403368077E+00 + 7.9069954211E+00 1.5126679784E+01 1.4775238047E-01 + 1.1331890874E+01 1.5262573023E+01 3.6402105874E+00 + 1.2526043578E-01 7.8407083341E+00 1.5266610338E+01 + 3.7359930492E+00 7.8335046351E+00 3.7936793473E+00 + 7.3045671580E+00 7.4192550656E+00 1.2479665327E-01 + 1.1474369578E+01 7.7262430431E+00 3.9843163641E+00 + 5.4946583696E-01 1.5115454234E+01 7.6973563030E+00 + 3.6481422032E+00 2.7419899923E-02 1.1211357086E+01 + 7.6534830328E+00 4.1453005141E-02 7.7998988718E+00 + 1.1514275816E+01 1.5118924317E+01 1.1659729708E+01 + 2.4256651369E-01 7.6578363812E+00 7.8079393082E+00 + 4.1473830211E+00 7.8153185021E+00 1.1434315921E+01 + 7.3392750121E+00 7.9157518024E+00 7.5200796868E+00 + 1.1477246416E+01 7.2993651895E+00 1.1437900893E+01 + 7.2566920375E-02 3.8989517192E+00 3.9030202431E+00 + 3.7240683968E+00 3.8444678323E+00 7.1587490148E-04 + 7.7761904917E+00 3.6503050973E+00 3.4776513302E+00 + 1.1350538939E+01 3.7916435740E+00 1.5151771937E+01 + 3.1636432532E-01 1.1387138566E+01 3.8869649019E+00 + 3.6361186675E+00 1.1502392341E+01 4.8567339049E-01 + 7.7727686640E+00 1.1612840429E+01 3.8390668079E+00 + 1.1083501355E+01 1.1451307009E+01 5.6709254980E-02 + 1.1618559869E-01 3.7082111283E+00 1.1238627092E+01 + 3.8094674183E+00 3.7021443576E+00 7.8761028184E+00 + 7.8390804081E+00 3.7607222157E+00 1.1483702806E+01 + 1.1336860789E+01 3.9278277750E+00 7.7601184107E+00 + 2.9458528744E-01 1.1468316076E+01 1.1465756641E+01 + 3.7089530864E+00 1.1234881848E+01 7.8579085900E+00 + 7.7767376436E+00 1.1654443547E+01 1.1630479466E+01 + 1.1560109676E+01 1.1476722258E+01 7.7610493735E+00 +:V: + -8.7472579262E-05 5.2109887313E-04 3.0849211586E-04 + 1.2140538515E-04 -3.7284457088E-05 3.3618046151E-04 + 3.7653674346E-04 -2.4562899434E-04 -2.9436505973E-04 + -1.7799786934E-04 -4.0395234129E-05 -2.5714344877E-04 + 2.0249992278E-04 2.9287681730E-04 -3.3418589039E-05 + -1.5466638969E-04 3.1438752382E-04 -3.7478555689E-05 + -5.0682197501E-04 -3.4906486875E-04 2.1524084182E-04 + 1.3129526204E-05 1.3467015058E-04 2.5561593886E-04 + 1.2317262462E-04 -2.7336447192E-04 5.7870400487E-05 + -2.2225619317E-04 4.2201605884E-05 -3.5130766929E-04 + 2.7941549547E-05 6.4260046376E-05 -2.4560547982E-04 + 1.0945608629E-04 -2.6467440566E-04 3.2345498675E-04 + 3.9578836162E-04 3.6048603352E-05 2.7437169314E-04 + 5.0028865577E-04 2.5511332273E-04 -4.9936155910E-05 + -4.6557072424E-04 4.2225067006E-04 -1.9411170939E-04 + 6.0765117465E-06 -5.7396099521E-04 -3.1925337461E-05 + 1.4887959304E-04 1.1206101060E-04 1.2834385735E-04 + -1.7960989711E-04 4.0177458979E-05 6.5315743392E-05 + 2.4149803477E-04 -2.8817955766E-04 -6.3983599628E-04 + -2.6378453739E-04 -3.7464617822E-06 -2.1824802166E-04 + 1.2549571521E-04 -1.3682960936E-04 9.7444923236E-05 + -3.1841268092E-04 5.7298945716E-05 4.2728511841E-05 + 2.5340913660E-04 2.3740634087E-04 -7.2621185024E-05 + -7.4758011537E-04 3.0678525522E-06 1.4597043972E-04 + 2.0859482869E-04 -1.6909844943E-04 -4.2566740596E-04 + -7.1792706932E-05 -1.9791222183E-04 4.5066632338E-04 + 3.9229391335E-04 -8.5899621724E-05 5.7754375528E-06 + -2.1887378519E-04 1.6585824689E-04 2.2950500158E-04 + 4.2901095254E-05 2.1899118948E-05 -7.9458765279E-05 + -3.0516320426E-04 -3.7501036030E-04 -4.7428403134E-04 + 3.2270275873E-04 3.1123713350E-04 2.0903984197E-04 + 1.1820694589E-04 2.0865415726E-05 2.7023237428E-04 +:F: + -2.1352199167E-03 -5.0511979699E-03 -1.2549916742E-03 + 1.0679377250E-02 4.3087051883E-04 -5.5858529029E-03 + -1.5160715148E-02 3.7856583450E-03 -6.4723660543E-03 + 8.6179796820E-03 -1.2573479190E-03 8.5841847163E-03 + -1.6469162264E-03 -6.2412750553E-03 -3.8655794363E-04 + -3.3837739575E-03 1.2953602615E-03 1.0418657584E-03 + 1.0220287081E-02 4.3133267661E-03 3.1473153681E-04 + 2.1767509268E-04 9.5858232379E-04 -1.1337421535E-03 + -2.2049538840E-02 7.2694420932E-05 -8.3122538703E-03 + 1.3341865425E-02 -2.8989797232E-03 1.5526501101E-02 + 1.4847346853E-03 1.1834015358E-04 2.0616876310E-03 + 6.5169970977E-03 4.5961028197E-04 -1.5201108660E-03 + -3.1255555080E-03 2.4284310000E-03 5.0218402471E-04 + -6.1766379088E-03 -5.3308301651E-03 1.6114642351E-03 + 9.0185289530E-03 -5.7601712530E-03 -8.9958423275E-04 + -1.6587712315E-03 -9.1523723758E-04 2.4947952735E-03 + 9.1466520958E-03 -2.1802922186E-03 -2.3198510190E-03 + -5.2003257234E-03 6.1092723763E-04 1.1073248496E-02 + 1.7033299026E-03 -3.4616178984E-03 -1.3901446144E-02 + -1.6866385959E-02 1.0650482263E-02 1.2812148589E-03 + 2.0659951295E-02 -2.9846532331E-03 1.6657145408E-03 + -1.6190782422E-04 5.9930956853E-05 1.5296207763E-02 + 3.5883667850E-03 -1.5730587811E-03 -1.6265978987E-02 + -2.0344937546E-02 2.9123007919E-03 5.8786689866E-03 + 2.4938353775E-03 3.6891916900E-03 -1.2043353552E-02 + -1.0684708636E-02 -8.2142519749E-04 8.9320231452E-03 + 1.3941415837E-02 2.0001654787E-03 -4.1306538784E-03 + -1.9620209794E-03 -2.7993161815E-03 1.0861714260E-02 + 9.9608774105E-03 4.6113695924E-03 -1.3351651100E-02 + -2.4963761065E-02 3.0460203679E-03 -2.0351436179E-03 + 1.7844492385E-02 7.3538354033E-04 -8.4666870520E-03 + -3.9151898850E-03 -9.0324315661E-04 1.0954018720E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5713477607E+03 +:LATVEC_SCALE: + 1.5285420147E+01 1.5285420147E+01 1.5285420147E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0784655616E+00 8.0176393506E-03 -9.4296187956E-03 + 8.0176393506E-03 7.7880687273E-01 1.7418133457E-01 + -9.4296187956E-03 1.7418133457E-01 9.0646454213E-01 +:STRESS: + -2.5161062334E+00 -3.4225096193E-01 1.3280558805E+00 + -3.4225096193E-01 1.4985862166E+00 3.8398535884E-02 + 1.3280558805E+00 3.8398535884E-02 -1.5245733600E+00 +:CONSTRESS: + 3.6763609147E+00 6.8820264583E-01 -2.6345429640E+00 + 6.8820264583E-01 -5.0939892869E+00 2.7116950449E-01 + -2.6345429640E+00 2.7116950449E-01 1.4176283722E+00 +:TOTSTRESS: + -8.1789119778E-02 -3.3793404455E-01 1.2970574647E+00 + -3.3793404455E-01 4.3742099430E+00 -1.3538670581E-01 + 1.2970574647E+00 -1.3538670581E-01 1.0134095299E+00 +:PRESIO: 9.2124565881E-01 +:PRES: 8.4736445891E-01 +:CONPRES: 1.0353665998E-13 +:TOTPRES: 1.7686101177E+00 +:PRESIG: 9.5096326070E-01 +:MIND: +Al - Al: 4.6892385190E+00 +Si - Si: 4.7542440272E+00 +Al - Si: 4.8586874597E+00 + + +:MDSTEP: 26 +:MDTM: 8.70 +:TWIST: 0 +:TEL: 1120 +:TIO: 1140.9378988297 +:TEN: -3.2407718743E+00 +:KEN: 5.2503372781E-03 +:KENIG: 5.4197029968E-03 +:FEN: -3.2460222116E+00 +:UEN: -3.2451890865E+00 +:TSEN: -8.3312503034E-04 +:NPH_HAMIL: -8.0812117409E-04 +:NPH_ENTHALPY: -1.0368233488E+02 +:R: + 3.6998023762E-01 3.4337927812E-01 1.9842808457E-01 + 3.8693329242E+00 1.5277275447E+01 4.0540161545E+00 + 7.9267509289E+00 1.5140686342E+01 1.4059664634E-01 + 1.1342569155E+01 1.5281825969E+01 3.6387105993E+00 + 1.3044607340E-01 7.8583537711E+00 1.5286047382E+01 + 3.7370905751E+00 7.8517219884E+00 3.7977918647E+00 + 7.3017411357E+00 7.4204626513E+00 1.3031041705E-01 + 1.1489931592E+01 7.7398520992E+00 3.9959481745E+00 + 5.5311659636E-01 1.5128733747E+01 7.7089614080E+00 + 3.6475490651E+00 2.8486341927E-02 1.1217613977E+01 + 7.6643478815E+00 4.3104859000E-02 7.8041674359E+00 + 1.1532322803E+01 1.5132426702E+01 1.1683234729E+01 + 2.5269948925E-01 7.6689142814E+00 7.8251238471E+00 + 4.1652768727E+00 7.8319979706E+00 1.1448267075E+01 + 7.3375121332E+00 7.9367132443E+00 7.5252371773E+00 + 1.1492625316E+01 7.2947949345E+00 1.1452309687E+01 + 7.6416138743E-02 3.9068985901E+00 3.9113761055E+00 + 3.7245204519E+00 3.8505737336E+00 2.4057503086E-03 + 7.7925234734E+00 3.6479730517E+00 3.4662928775E+00 + 1.1358955769E+01 3.7966487773E+00 1.5166475892E+01 + 3.2002570705E-01 1.1398840793E+01 3.8945559687E+00 + 3.6330367182E+00 1.1519087627E+01 4.8747153852E-01 + 7.7894042900E+00 1.1634145996E+01 3.8422623237E+00 + 1.1079526311E+01 1.1466604654E+01 6.0445498615E-02 + 1.2153589183E-01 3.7089566991E+00 1.1242903549E+01 + 3.8126777953E+00 3.7021390635E+00 7.8978072206E+00 + 7.8593159576E+00 3.7635938150E+00 1.1499068335E+01 + 1.1346464621E+01 3.9371454628E+00 7.7761872800E+00 + 2.9610191104E-01 1.1484114254E+01 1.1478925833E+01 + 3.7061476926E+00 1.1240502334E+01 7.8565491531E+00 + 7.7951854173E+00 1.1677652032E+01 1.1651062412E+01 + 1.1578370493E+01 1.1492472740E+01 7.7781316108E+00 +:V: + -8.8364147016E-05 5.1782562404E-04 3.0743890336E-04 + 1.2664208206E-04 -3.7044456021E-05 3.3288253176E-04 + 3.6821135603E-04 -2.4331186923E-04 -2.9725120342E-04 + -1.7334893986E-04 -4.0982271930E-05 -2.5240836145E-04 + 2.0138423082E-04 2.8933785699E-04 -3.3567010576E-05 + -1.5618357158E-04 3.1463683921E-04 -3.6945520898E-05 + -5.0097186133E-04 -3.4640287828E-04 2.1505603152E-04 + 1.3259187869E-05 1.3500922591E-04 2.5476164999E-04 + 1.1179370988E-04 -2.7300655962E-04 5.3527813321E-05 + -2.1514701934E-04 4.0597831996E-05 -3.4285605410E-04 + 2.8647603457E-05 6.4285418674E-05 -2.4416781271E-04 + 1.1267545222E-04 -2.6411912491E-04 3.2218866461E-04 + 3.9357875054E-04 3.7218636686E-05 2.7425183239E-04 + 4.9654097219E-04 2.5208524401E-04 -4.8979185585E-05 + -4.6029374023E-04 4.1873622990E-04 -1.9437746838E-04 + 5.2857496856E-06 -5.7361679015E-04 -3.0614624394E-05 + 1.5320992535E-04 1.1089471865E-04 1.2700121015E-04 + -1.8194880805E-04 4.0444238597E-05 7.0575457665E-05 + 2.4195507523E-04 -2.8953831725E-04 -6.4568692239E-04 + -2.7167616320E-04 1.4658448317E-06 -2.1732203094E-04 + 1.3531904259E-04 -1.3811936753E-04 9.8163561286E-05 + -3.1801913853E-04 5.7281104981E-05 5.0096666862E-05 + 2.5470484394E-04 2.3630761951E-04 -8.0346220651E-05 + -7.5629033072E-04 4.3816137571E-06 1.4856710152E-04 + 2.0946161868E-04 -1.6707299831E-04 -4.3093682689E-04 + -7.6864032014E-05 -1.9803384330E-04 4.5425822157E-04 + 3.9854116240E-04 -8.4859015560E-05 3.7845628484E-06 + -2.1955353746E-04 1.6423463479E-04 2.3452124524E-04 + 4.7639995524E-05 2.4171227550E-05 -8.5778524595E-05 + -3.1690723670E-04 -3.7292564336E-04 -4.7468542827E-04 + 3.3084186435E-04 3.1119793734E-04 2.0469490099E-04 + 1.1623707920E-04 2.0364478729E-05 2.7511241843E-04 +:F: + -1.8632647056E-03 -5.1961554369E-03 -1.3012620728E-03 + 1.0740375589E-02 3.2542207034E-04 -5.7324413870E-03 + -1.5895495232E-02 4.1168112639E-03 -6.5296756074E-03 + 8.8937754066E-03 -1.2847494359E-03 8.8530314682E-03 + -1.7149707583E-03 -6.2614483021E-03 -3.7827580804E-04 + -3.4506936317E-03 1.3482117506E-03 8.7630232511E-04 + 1.0328083126E-02 4.4135811535E-03 8.4582215370E-05 + 3.6585267807E-04 1.0954976993E-03 -9.1151651913E-04 + -2.2457464750E-02 -9.0653848201E-05 -8.6158976477E-03 + 1.3700038899E-02 -3.2430534485E-03 1.6163438572E-02 + 1.4641620632E-03 3.2033419914E-04 2.3509467415E-03 + 6.8342595026E-03 3.5134374536E-04 -1.8029456644E-03 + -3.5600873264E-03 2.4043529159E-03 4.6587671790E-04 + -6.0631023896E-03 -5.3432507942E-03 1.9231576012E-03 + 9.4722945320E-03 -5.9643884732E-03 -1.1762277307E-03 + -1.4474069860E-03 -7.3901646529E-04 2.5385441917E-03 + 9.5554911822E-03 -2.0235780510E-03 -2.5230581475E-03 + -5.4444091632E-03 7.1102544221E-04 1.1010464446E-02 + 1.5073442556E-03 -3.7290912887E-03 -1.3771022578E-02 + -1.7175544109E-02 1.0858975204E-02 1.3483275841E-03 + 2.0603962916E-02 -3.0922027439E-03 1.8363042637E-03 + 4.3411754094E-05 1.8012070504E-04 1.5372893580E-02 + 3.1519271117E-03 -1.6650240977E-03 -1.6041185860E-02 + -1.9728634014E-02 2.5314171457E-03 5.6468128631E-03 + 2.2291984035E-03 3.7510104406E-03 -1.2054042267E-02 + -1.0656289451E-02 -7.6494595279E-04 8.3734414289E-03 + 1.4012201462E-02 1.8278388111E-03 -4.0613288726E-03 + -2.0444963117E-03 -2.9986925016E-03 1.1115361970E-02 + 9.8488133195E-03 4.8936262078E-03 -1.3188244443E-02 + -2.5217705641E-02 3.5109451972E-03 -2.2203977898E-03 + 1.7542784348E-02 8.0730184281E-04 -8.3358414770E-03 + -3.5744120809E-03 -1.0515649541E-03 1.0683877903E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5855917116E+03 +:LATVEC_SCALE: + 1.5305714629E+01 1.5305714629E+01 1.5305714629E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0805037669E+00 1.0653037617E-02 -1.4357316075E-02 + 1.0653037617E-02 7.6919242232E-01 1.7345290301E-01 + -1.4357316075E-02 1.7345290301E-01 9.0747672545E-01 +:STRESS: + -2.2826409404E+00 -3.5044436259E-01 1.3533806703E+00 + -3.5044436259E-01 1.5622817414E+00 3.7595871924E-02 + 1.3533806703E+00 3.7595871924E-02 -1.2297505980E+00 +:CONSTRESS: + 3.6087765175E+00 7.0906548707E-01 -2.6964960833E+00 + 7.0906548707E-01 -4.8349189225E+00 2.7166804926E-01 + -2.6964960833E+00 2.7166804926E-01 1.2261424050E+00 +:TOTSTRESS: + -2.4563181018E-01 -3.4796808686E-01 1.3287580969E+00 + -3.4796808686E-01 4.0418296034E+00 -1.3581101818E-01 + 1.3287580969E+00 -1.3581101818E-01 9.1108491843E-01 +:PRESIO: 9.1905763822E-01 +:PRES: 6.5003659899E-01 +:CONPRES: 2.2594649804E-14 +:TOTPRES: 1.5690942372E+00 +:PRESIG: 9.4870465881E-01 +:MIND: +Al - Al: 4.6827739570E+00 +Si - Si: 4.7538116891E+00 +Al - Si: 4.8420339809E+00 + + +:MDSTEP: 27 +:MDTM: 6.01 +:TWIST: 0 +:TEL: 1120 +:TIO: 1142.83267647802 +:TEN: -3.2407943562E+00 +:KEN: 5.2590566149E-03 +:KENIG: 5.4287036024E-03 +:FEN: -3.2460534128E+00 +:UEN: -3.2452363285E+00 +:TSEN: -8.1708425035E-04 +:NPH_HAMIL: -8.0299963648E-04 +:NPH_ENTHALPY: -1.0368232975E+02 +:R: + 3.6827148721E-01 3.5667052610E-01 2.0632310186E-01 + 3.8777510741E+00 1.5296909516E+01 4.0677022211E+00 + 7.9464607421E+00 1.5155037098E+01 1.3336170779E-01 + 1.1353578068E+01 1.5301358266E+01 3.6373917494E+00 + 1.3561283852E-01 7.8760728364E+00 1.5305775218E+01 + 3.7382170621E+00 7.8701081743E+00 3.8019887705E+00 + 7.2991854423E+00 7.4218688414E+00 1.3582785354E-01 + 1.1505720343E+01 7.7536245810E+00 4.0076459367E+00 + 5.5649678789E-01 1.5142304508E+01 7.7206076574E+00 + 3.6471979678E+00 2.9512728676E-02 1.1224290071E+01 + 7.6753792678E+00 4.4761586909E-02 7.8086162302E+00 + 1.1550678416E+01 1.5146225947E+01 1.1706943193E+01 + 2.6279292715E-01 7.6801705885E+00 7.8424656343E+00 + 4.1831755246E+00 7.8487620434E+00 1.1462463641E+01 + 7.3360095727E+00 7.9577536071E+00 7.5305253442E+00 + 1.1508208289E+01 7.2903562118E+00 1.1466971689E+01 + 8.0381894195E-02 3.9148966943E+00 3.9197772839E+00 + 3.7249789194E+00 3.8567626572E+00 4.2282053046E-03 + 7.8090253631E+00 3.6456665341E+00 3.4548354382E+00 + 1.1367385404E+01 3.8018580659E+00 1.5181489210E+01 + 3.2394128777E-01 1.1410726135E+01 3.9022444752E+00 + 3.6300253947E+00 1.1536007820E+01 4.8946413403E-01 + 7.8062285605E+00 1.1655656566E+01 3.8453390486E+00 + 1.1075527733E+01 1.1482154462E+01 6.4250930650E-02 + 1.2691545274E-01 3.7098190476E+00 1.1247252131E+01 + 3.8158336139E+00 3.7021960557E+00 7.9197652869E+00 + 7.8798722608E+00 3.7665601402E+00 1.1514607317E+01 + 1.1356263129E+01 3.9465032570E+00 7.7925403630E+00 + 2.9774280308E-01 1.1500193369E+01 1.1492158214E+01 + 3.7031103409E+00 1.1246382236E+01 7.8553146892E+00 + 7.8139951631E+00 1.1701096146E+01 1.1671770397E+01 + 1.1596812205E+01 1.1508432774E+01 7.7954929246E+00 +:V: + -8.9118863541E-05 5.1447995457E-04 3.0635961256E-04 + 1.3189526301E-04 -3.6856575712E-05 3.2951182571E-04 + 3.5952068484E-04 -2.4081919540E-04 -3.0015507745E-04 + -1.6856686600E-04 -4.1579428107E-05 -2.4754075003E-04 + 2.0023514249E-04 2.8579178613E-04 -3.3711746620E-05 + -1.5772587872E-04 3.1490233667E-04 -3.6499199387E-05 + -4.9507245878E-04 -3.4369180560E-04 2.1475024478E-04 + 1.3463889263E-05 1.3541290936E-04 2.5401991851E-04 + 1.0022892876E-04 -2.7272836798E-04 4.9041780314E-05 + -2.0786699802E-04 3.8821625758E-05 -3.3409124138E-04 + 2.9343410017E-05 6.4412549626E-05 -2.4258409431E-04 + 1.1604973283E-04 -2.6361414649E-04 3.2077581546E-04 + 3.9114455808E-04 3.8368955572E-05 2.7410879707E-04 + 4.9285201586E-04 2.4905557289E-04 -4.7864291800E-05 + -4.5479082883E-04 4.1511803364E-04 -1.9477942852E-04 + 4.6051066664E-06 -5.7317090948E-04 -2.9283386644E-05 + 1.5772424751E-04 1.0980489620E-04 1.2555908043E-04 + -1.8440087416E-04 4.0759274639E-05 7.5793168136E-05 + 2.4232172995E-04 -2.9101702306E-04 -6.5145348398E-04 + -2.7969849489E-04 6.7658693007E-06 -2.1635891202E-04 + 1.4508838129E-04 -1.3945380053E-04 9.8956018951E-05 + -3.1752489234E-04 5.7320493255E-05 5.7486946336E-05 + 2.5578640748E-04 2.3516061072E-04 -8.7947652510E-05 + -7.6466549449E-04 5.5024836976E-06 1.5105123155E-04 + 2.1019327844E-04 -1.6501905360E-04 -4.3618857363E-04 + -8.1908953072E-05 -1.9811960277E-04 4.5756414482E-04 + 4.0480049389E-04 -8.3906064737E-05 1.8310741215E-06 + -2.2026983400E-04 1.6251417612E-04 2.3963474049E-04 + 5.2320087561E-05 2.6575192733E-05 -9.2007395029E-05 + -3.2874363723E-04 -3.7061191540E-04 -4.7515722502E-04 + 3.3880820711E-04 3.1118440412E-04 2.0040996600E-04 + 1.1443140029E-04 1.9791343033E-05 2.7985020106E-04 +:F: + -1.6030100892E-03 -5.3198986282E-03 -1.3426638187E-03 + 1.0781355839E-02 2.2272789283E-04 -5.8689612068E-03 + -1.6628760696E-02 4.4776168050E-03 -6.5787069237E-03 + 9.1589094315E-03 -1.3034686456E-03 9.1176025860E-03 + -1.7713458092E-03 -6.2681079265E-03 -3.7505157899E-04 + -3.5023961818E-03 1.3828077034E-03 6.9801699856E-04 + 1.0412016954E-02 4.4981029952E-03 -1.5135321657E-04 + 5.1706697694E-04 1.2261669498E-03 -6.7387826819E-04 + -2.2839628327E-02 -2.6076637110E-04 -8.9007857819E-03 + 1.4042539581E-02 -3.5889203130E-03 1.6790288970E-02 + 1.4497989212E-03 5.2676031557E-04 2.6318974328E-03 + 7.1566439259E-03 2.4455038463E-04 -2.0858651724E-03 + -4.0010805196E-03 2.3589988090E-03 4.2867255385E-04 + -5.9288920244E-03 -5.3356562286E-03 2.2398170996E-03 + 9.9110130126E-03 -6.1613879338E-03 -1.4550134775E-03 + -1.2256071213E-03 -5.4986110070E-04 2.5810568581E-03 + 9.9416379799E-03 -1.8628223643E-03 -2.7289781672E-03 + -5.6938027341E-03 8.1465603625E-04 1.0933865359E-02 + 1.3500006610E-03 -3.9855478587E-03 -1.3632006045E-02 + -1.7469485903E-02 1.1041673709E-02 1.4239339009E-03 + 2.0500935391E-02 -3.1863151161E-03 1.9817277666E-03 + 2.3320515781E-04 3.0037526994E-04 1.5431859150E-02 + 2.7294002892E-03 -1.7614522177E-03 -1.5803833781E-02 + -1.9063800312E-02 2.1231134060E-03 5.4389026470E-03 + 1.9556191277E-03 3.8059562504E-03 -1.2030641162E-02 + -1.0609182919E-02 -6.8832250053E-04 7.8034804262E-03 + 1.4054657800E-02 1.6376933000E-03 -3.9869307768E-03 + -2.1326220348E-03 -3.1964096838E-03 1.1308112549E-02 + 9.7475317208E-03 5.1703042145E-03 -1.3017282286E-02 + -2.5433032441E-02 3.9764607026E-03 -2.3625712106E-03 + 1.7199737570E-02 8.6372730841E-04 -8.2279332394E-03 + -3.2394232264E-03 -1.2027551642E-03 1.0413221814E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6000820162E+03 +:LATVEC_SCALE: + 1.5326305035E+01 1.5326305035E+01 1.5326305035E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0826593596E+00 1.3289579090E-02 -1.9034291298E-02 + 1.3289579090E-02 7.5953203286E-01 1.7270208614E-01 + -1.9034291298E-02 1.7270208614E-01 9.0844438118E-01 +:STRESS: + -2.0545423266E+00 -3.5932500733E-01 1.3770084110E+00 + -3.5932500733E-01 1.6315357906E+00 3.7024884240E-02 + 1.3770084110E+00 3.7024884240E-02 -9.4133803205E-01 +:CONSTRESS: + 3.5484401158E+00 7.3132631772E-01 -2.7547636721E+00 + 7.3132631772E-01 -4.5908711903E+00 2.7156511411E-01 + -2.7547636721E+00 2.7156511411E-01 1.0424310745E+00 +:TOTSTRESS: + -4.1123842963E-01 -3.5871173130E-01 1.3587209698E+00 + -3.5871173130E-01 3.7188674326E+00 -1.3588791220E-01 + 1.3587209698E+00 -1.3588791220E-01 8.0735133874E-01 +:PRESIO: 9.1687859121E-01 +:PRES: 4.5478152269E-01 +:CONPRES: 0.0000000000E+00 +:TOTPRES: 1.3716601139E+00 +:PRESIG: 9.4645531996E-01 +:MIND: +Al - Al: 4.6769447454E+00 +Si - Si: 4.7532049482E+00 +Al - Si: 4.8255469524E+00 + + +:MDSTEP: 28 +:MDTM: 6.01 +:TWIST: 0 +:TEL: 1120 +:TIO: 1144.79791800463 +:TEN: -3.2408142953E+00 +:KEN: 5.2681002104E-03 +:KENIG: 5.4380389268E-03 +:FEN: -3.2460823955E+00 +:UEN: -3.2452800451E+00 +:TSEN: -8.0235041182E-04 +:NPH_HAMIL: -8.0353980240E-04 +:NPH_ENTHALPY: -1.0368233029E+02 +:R: + 3.6654862320E-01 3.6990112843E-01 2.1420477092E-01 + 3.8863674880E+00 1.5316795527E+01 4.0813811453E+00 + 7.9660918199E+00 1.5169690711E+01 1.2604642501E-01 + 1.1364886584E+01 1.5321123459E+01 3.6362462711E+00 + 1.4075969561E-01 7.8938417769E+00 1.5325747653E+01 + 3.7393605098E+00 7.8886399885E+00 3.8062563361E+00 + 7.2968788917E+00 7.4234521459E+00 1.4134568368E-01 + 1.1521702990E+01 7.7675387672E+00 4.0194006278E+00 + 5.5959997759E-01 1.5156118552E+01 7.7322681863E+00 + 3.6470821087E+00 3.0494653198E-02 1.1231359199E+01 + 7.6865538472E+00 4.6425665566E-02 7.8132250978E+00 + 1.1569311864E+01 1.5160274872E+01 1.1730816334E+01 + 2.7284066623E-01 7.6915815590E+00 7.8599406328E+00 + 4.2010682230E+00 7.8655872138E+00 1.1476874956E+01 + 7.3347504934E+00 7.9788465588E+00 7.5359178767E+00 + 1.1523963364E+01 7.2860291453E+00 1.1481852794E+01 + 8.4468657350E-02 3.9229361882E+00 3.9282095135E+00 + 3.7254294738E+00 3.8630242207E+00 6.1823390041E-03 + 7.8256707846E+00 3.6433713312E+00 3.4432699862E+00 + 1.1375789862E+01 3.8072621641E+00 1.5196766873E+01 + 3.2810891381E-01 1.1422758947E+01 3.9100204284E+00 + 3.6270758918E+00 1.1553119553E+01 4.9165043619E-01 + 7.8232129223E+00 1.1677335877E+01 3.8482881875E+00 + 1.1071479864E+01 1.1497916851E+01 6.8122917481E-02 + 1.3232069116E-01 3.7107875671E+00 1.1251638977E+01 + 3.8189238826E+00 3.7023049969E+00 7.9419464300E+00 + 7.9007262013E+00 3.7696074961E+00 1.1530285876E+01 + 1.1366220872E+01 3.9558869259E+00 7.8091565484E+00 + 2.9950586951E-01 1.1516522038E+01 1.1505421099E+01 + 3.6998271183E+00 1.1252493047E+01 7.8541795747E+00 + 7.8331392985E+00 1.1724741361E+01 1.1692569553E+01 + 1.1615403870E+01 1.1524565797E+01 7.8131066338E+00 +:V: + -8.9743041221E-05 5.1107477838E-04 3.0525774165E-04 + 1.3715525511E-04 -3.6719537394E-05 3.2607503855E-04 + 3.5046758140E-04 -2.3813700031E-04 -3.0307289769E-04 + -1.6365842397E-04 -4.2182461084E-05 -2.4254433895E-04 + 1.9906008256E-04 2.8224583239E-04 -3.3855510155E-05 + -1.5928584758E-04 3.1517579611E-04 -3.6145601791E-05 + -4.8913757197E-04 -3.4094084434E-04 2.1432110787E-04 + 1.3745343829E-05 1.3587828970E-04 2.5339957824E-04 + 8.8493164026E-05 -2.7253375592E-04 4.4422732558E-05 + -2.0042565860E-04 3.6872874952E-05 -3.2502130915E-04 + 3.0031582623E-05 6.4643077693E-05 -2.4085993018E-04 + 1.1958142783E-04 -2.6315909888E-04 3.1921790016E-04 + 3.8848389512E-04 3.9488712180E-05 2.7394322004E-04 + 4.8923304820E-04 2.4603524828E-04 -4.6589805032E-05 + -4.4907214164E-04 4.1140159926E-04 -1.9531900421E-04 + 4.0393667141E-06 -5.7261868437E-04 -2.7932752498E-05 + 1.6241153205E-04 1.0879312559E-04 1.2401682001E-04 + -1.8696921792E-04 4.1124246866E-05 8.0962344738E-05 + 2.4261752324E-04 -2.9261124268E-04 -6.5713425118E-04 + -2.8784462194E-04 1.2140138915E-05 -2.1535423290E-04 + 1.5478188670E-04 -1.4082647963E-04 9.9810972704E-05 + -3.1693824831E-04 5.7416994320E-05 6.4890838225E-05 + 2.5666178274E-04 2.3396456384E-04 -9.5419298856E-05 + -7.7268633754E-04 6.4183426571E-06 1.5343487361E-04 + 2.1078765425E-04 -1.6294060158E-04 -4.4140848156E-04 + -8.6919017564E-05 -1.9816102500E-04 4.6058102377E-04 + 4.1105903769E-04 -8.3049350177E-05 -8.2794778745E-08 + -2.2102566611E-04 1.6069898519E-04 2.4481663247E-04 + 5.6947434689E-05 2.9107663105E-05 -9.8142896075E-05 + -3.4065434817E-04 -3.6807020061E-04 -4.7567988874E-04 + 3.4658271685E-04 3.1118993655E-04 1.9617467622E-04 + 1.1278759981E-04 1.9144754678E-05 2.8444679823E-04 +:F: + -1.3543844925E-03 -5.4207437764E-03 -1.3790870909E-03 + 1.0803139390E-02 1.2255294898E-04 -5.9938540126E-03 + -1.7359731890E-02 4.8684343662E-03 -6.6178053062E-03 + 9.4112265479E-03 -1.3136620093E-03 9.3760564372E-03 + -1.8127218257E-03 -6.2636077435E-03 -3.7712212808E-04 + -3.5381055150E-03 1.3993031426E-03 5.0864445112E-04 + 1.0472142803E-02 4.5667056822E-03 -3.9423731426E-04 + 6.7230564967E-04 1.3502690780E-03 -4.1920817345E-04 + -2.3192253341E-02 -4.3647623084E-04 -9.1649983925E-03 + 1.4367323420E-02 -3.9350710147E-03 1.7402100504E-02 + 1.4392774004E-03 7.3502829226E-04 2.9028729678E-03 + 7.4836794204E-03 1.4078510957E-04 -2.3678011973E-03 + -4.4494199401E-03 2.2914511997E-03 3.9137622224E-04 + -5.7768798098E-03 -5.3081292877E-03 2.5597130058E-03 + 1.0332001633E-02 -6.3498274631E-03 -1.7356635967E-03 + -9.9481735451E-04 -3.4749133988E-04 2.6209744225E-03 + 1.0304561590E-02 -1.7006970935E-03 -2.9372153013E-03 + -5.9493996815E-03 9.2148462984E-04 1.0843631150E-02 + 1.2311235910E-03 -4.2318716521E-03 -1.3487699200E-02 + -1.7748369118E-02 1.1195651759E-02 1.5124485092E-03 + 2.0353916238E-02 -3.2659649821E-03 2.1047994639E-03 + 4.0888984636E-04 4.1967770678E-04 1.5473797613E-02 + 2.3215227596E-03 -1.8599447340E-03 -1.5552752872E-02 + -1.8357450636E-02 1.6911800159E-03 5.2545898355E-03 + 1.6787541203E-03 3.8538555395E-03 -1.1977885752E-02 + -1.0545355884E-02 -5.9412031064E-04 7.2252562803E-03 + 1.4068054806E-02 1.4306367064E-03 -3.9084644047E-03 + -2.2249480158E-03 -3.3899015610E-03 1.1440762524E-02 + 9.6601661817E-03 5.4394441387E-03 -1.2842812462E-02 + -2.5610347000E-02 4.4434700023E-03 -2.4615396688E-03 + 1.6815082995E-02 9.0456756011E-04 -8.1427005992E-03 + -2.9089838892E-03 -1.3569886789E-03 1.0143824085E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6147877048E+03 +:LATVEC_SCALE: + 1.5347145087E+01 1.5347145087E+01 1.5347145087E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0849485124E+00 1.5916384143E-02 -2.3454274787E-02 + 1.5916384143E-02 7.4984516536E-01 1.7191828177E-01 + -2.3454274787E-02 1.7191828177E-01 9.0936276653E-01 +:STRESS: + -1.8325549884E+00 -3.6900350734E-01 1.3986745822E+00 + -3.6900350734E-01 1.7054300449E+00 3.6892879963E-02 + 1.3986745822E+00 3.6892879963E-02 -6.6134787974E-01 +:CONSTRESS: + 3.4944430480E+00 7.5506353462E-01 -2.8088925439E+00 + 7.5506353462E-01 -4.3624969483E+00 2.7073715017E-01 + -2.8088925439E+00 2.7073715017E-01 8.6805390031E-01 +:TOTSTRESS: + -5.7693954722E-01 -3.7014364313E-01 1.3867636869E+00 + -3.7014364313E-01 3.4069120688E+00 -1.3571174836E-01 + 1.3867636869E+00 -1.3571174836E-01 7.0265674597E-01 +:PRESIO: 9.1471881475E-01 +:PRES: 2.6282427442E-01 +:CONPRES: -3.4157794115E-14 +:TOTPRES: 1.1775430892E+00 +:PRESIG: 9.4422587329E-01 +:MIND: +Al - Al: 4.6717507920E+00 +Si - Si: 4.7524131148E+00 +Al - Si: 4.8092320918E+00 + + +:MDSTEP: 29 +:MDTM: 6.05 +:TWIST: 0 +:TEL: 1120 +:TIO: 1146.8367023554 +:TEN: -3.2408318233E+00 +:KEN: 5.2774822333E-03 +:KENIG: 5.4477235956E-03 +:FEN: -3.2461093055E+00 +:UEN: -3.2453202812E+00 +:TSEN: -7.8902430301E-04 +:NPH_HAMIL: -8.1599808436E-04 +:NPH_ENTHALPY: -1.0368234275E+02 +:R: + 3.6481365342E-01 3.8306890259E-01 2.2207210666E-01 + 3.8951710717E+00 1.5336887225E+01 4.0950394808E+00 + 7.9856117189E+00 1.5184607442E+01 1.1864983647E-01 + 1.1376464431E+01 1.5341076403E+01 3.6352666437E+00 + 1.4588577812E-01 7.9116375544E+00 1.5345919636E+01 + 3.7405094342E+00 7.9072945710E+00 3.8105809977E+00 + 7.2948006457E+00 7.4251915085E+00 1.4686052039E-01 + 1.1537847638E+01 7.7815734421E+00 4.0312037155E+00 + 5.6242012819E-01 1.5170129071E+01 7.7439169857E+00 + 3.6471947811E+00 3.1427701077E-02 1.1238795932E+01 + 7.6978489208E+00 4.8099588965E-02 7.8179744049E+00 + 1.1588193303E+01 1.5174527561E+01 1.1754816268E+01 + 2.8283641599E-01 7.7031237684E+00 7.8775253793E+00 + 4.2189446925E+00 7.8824508032E+00 1.1491471301E+01 + 7.3337184795E+00 7.9999664373E+00 7.5413890597E+00 + 1.1539859584E+01 7.2817946802E+00 1.1496919767E+01 + 8.8680603586E-02 3.9310075359E+00 3.9366587905E+00 + 3.7258580339E+00 3.8693483769E+00 8.2670765532E-03 + 7.8424354017E+00 3.6410736797E+00 3.4315879248E+00 + 1.1384132276E+01 3.8128517485E+00 1.5212265238E+01 + 3.3252590791E-01 1.1434904671E+01 3.9178738581E+00 + 3.6241795657E+00 1.1570390348E+01 4.9402953060E-01 + 7.8403295735E+00 1.1699148522E+01 3.8511014234E+00 + 1.1067358426E+01 1.1513852854E+01 7.2059092747E-02 + 1.3774795642E-01 3.7118518818E+00 1.1256031525E+01 + 3.8219381212E+00 3.7024560806E+00 7.9643205175E+00 + 7.9218548727E+00 3.7727222915E+00 1.1546071089E+01 + 1.1376303278E+01 3.9652825737E+00 7.8260145786E+00 + 3.0138920025E-01 1.1533069684E+01 1.1518682756E+01 + 3.6962849053E+00 1.1258807216E+01 7.8531193917E+00 + 7.8525903050E+00 1.1748553833E+01 1.1713426624E+01 + 1.1634115384E+01 1.1540836110E+01 7.8309466436E+00 +:V: + -9.0242944110E-05 5.0762354959E-04 3.0413664674E-04 + 1.4241273521E-04 -3.6631933163E-05 3.2257885464E-04 + 3.4105499062E-04 -2.3525130906E-04 -3.0600020878E-04 + -1.5863144130E-04 -4.2787249130E-05 -2.3742353258E-04 + 1.9786700130E-04 2.7870644501E-04 -3.4001355636E-05 + -1.6085551059E-04 3.1544852326E-04 -3.5889860116E-05 + -4.8318019593E-04 -3.3815911533E-04 2.1376613714E-04 + 1.4105329813E-05 1.3640238945E-04 2.5290940299E-04 + 7.6602398842E-05 -2.7242596073E-04 3.9681740953E-05 + -1.9283313703E-04 3.4752053623E-05 -3.1565572343E-04 + 3.0714520756E-05 6.4977531757E-05 -2.3900148856E-04 + 1.2327275130E-04 -2.6275328491E-04 3.1751682191E-04 + 3.8559464723E-04 4.0566483772E-05 2.7375602726E-04 + 4.8569380388E-04 2.4303534303E-04 -4.5155191675E-05 + -4.4314872843E-04 4.0759278530E-04 -1.9599754141E-04 + 3.5928714544E-06 -5.7195502827E-04 -2.6563724044E-05 + 1.6726067276E-04 1.0785984864E-04 1.2237395165E-04 + -1.8965700723E-04 4.1540158069E-05 8.6076874919E-05 + 2.4286246225E-04 -2.9431629561E-04 -6.6272955461E-04 + -2.9610762952E-04 1.7574786606E-05 -2.1430163869E-04 + 1.6437852518E-04 -1.4223053047E-04 1.0071812719E-04 + -3.1626705260E-04 5.7570509352E-05 7.2300241466E-05 + 2.5733957252E-04 2.3271928706E-04 -1.0275502529E-04 + -7.8033661135E-04 7.1182101221E-06 1.5572982285E-04 + 2.1124425659E-04 -1.6084150243E-04 -4.4658437304E-04 + -9.1887120632E-05 -1.9814976366E-04 4.6330712368E-04 + 4.1730378485E-04 -8.2296924335E-05 -1.9550883308E-06 + -2.2182353278E-04 1.5879186105E-04 2.5003846687E-04 + 6.1529258003E-05 3.1764185446E-05 -1.0418406820E-04 + -3.5262178503E-04 -3.6530162258E-04 -4.7623349037E-04 + 3.5414694516E-04 3.1120762842E-04 1.9197883676E-04 + 1.1130381689E-04 1.8423516542E-05 2.8890414050E-04 +:F: + -1.1172873313E-03 -5.4978561541E-03 -1.4110366789E-03 + 1.0806101389E-02 2.5622546265E-05 -6.1084487455E-03 + -1.8088409328E-02 5.2888386766E-03 -6.6459500530E-03 + 9.6484573619E-03 -1.3156206547E-03 9.6272675175E-03 + -1.8401778252E-03 -6.2484107670E-03 -3.8562677095E-04 + -3.5565636117E-03 1.3957279017E-03 3.0996038440E-04 + 1.0511150540E-02 4.6195951377E-03 -6.4328549729E-04 + 8.3085797118E-04 1.4678917976E-03 -1.4917366048E-04 + -2.3514238385E-02 -6.1662901651E-04 -9.4076996609E-03 + 1.4673659467E-02 -4.2806363972E-03 1.7997876139E-02 + 1.4341124283E-03 9.4336870624E-04 3.1631502663E-03 + 7.8146626148E-03 3.9664379451E-05 -2.6479101571E-03 + -4.9049266784E-03 2.2002563375E-03 3.5445369467E-04 + -5.6098629206E-03 -5.2597937779E-03 2.8800433874E-03 + 1.0733988092E-02 -6.5293970351E-03 -2.0182708866E-03 + -7.5527868460E-04 -1.3071839730E-04 2.6600922586E-03 + 1.0644324654E-02 -1.5391368514E-03 -3.1473757700E-03 + -6.2105108872E-03 1.0290720242E-03 1.0741094442E-02 + 1.1530590664E-03 -4.4662068373E-03 -1.3342085006E-02 + -1.8011806248E-02 1.1321943526E-02 1.6173113286E-03 + 2.0162764313E-02 -3.3303110775E-03 2.2069084212E-03 + 5.7077506040E-04 5.3914466807E-04 1.5499412103E-02 + 1.9303007889E-03 -1.9604674634E-03 -1.5288999574E-02 + -1.7614866170E-02 1.2363936547E-03 5.0932121380E-03 + 1.3998441056E-03 3.8952426466E-03 -1.1899136421E-02 + -1.0468196452E-02 -4.8032862660E-04 6.6411559774E-03 + 1.4052398244E-02 1.2078122452E-03 -3.8259821580E-03 + -2.3209717872E-03 -3.5787799532E-03 1.1513920458E-02 + 9.5882359565E-03 5.6983763879E-03 -1.2666843458E-02 + -2.5750591216E-02 4.9104609492E-03 -2.5158575320E-03 + 1.6391350487E-02 9.2872717064E-04 -8.0795307936E-03 + -2.5823550140E-03 -1.5138457469E-03 9.8773543078E-03 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6296783280E+03 +:LATVEC_SCALE: + 1.5368189704E+01 1.5368189704E+01 1.5368189704E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0873865359E+00 1.8522069748E-02 -2.7614053225E-02 + 1.8522069748E-02 7.4014985090E-01 1.7109147274E-01 + -2.7614053225E-02 1.7109147274E-01 9.1022930760E-01 +:STRESS: + -1.6171662846E+00 -3.7951501503E-01 1.4181722086E+00 + -3.7951501503E-01 1.7832091519E+00 3.7166746843E-02 + 1.4181722086E+00 3.7166746843E-02 -3.9162453246E-01 +:CONSTRESS: + 3.4457744176E+00 7.8039959919E-01 -2.8584038259E+00 + 7.8039959919E-01 -4.1503493883E+00 2.6899124327E-01 + -2.8584038259E+00 2.6899124327E-01 7.0457497062E-01 +:TOTSTRESS: + -7.4122159722E-01 -3.8236251441E-01 1.4126175642E+00 + -3.8236251441E-01 3.1072900872E+00 -1.3506651737E-01 + 1.4126175642E+00 -1.3506651737E-01 5.9727886944E-01 +:PRESIO: 9.1258856479E-01 +:PRES: 7.5193888356E-02 +:CONPRES: 1.4809463849E-13 +:TOTPRES: 9.8778245314E-01 +:PRESIG: 9.4202690559E-01 +:MIND: +Al - Al: 4.6671917041E+00 +Si - Si: 4.7514261176E+00 +Al - Si: 4.7930963596E+00 + + +:MDSTEP: 30 +:MDTM: 6.02 +:TWIST: 0 +:TEL: 1120 +:TIO: 1148.95210921797 +:TEN: -3.2408470244E+00 +:KEN: 5.2872168556E-03 +:KENIG: 5.4577722380E-03 +:FEN: -3.2461342413E+00 +:UEN: -3.2453570392E+00 +:TSEN: -7.7720213873E-04 +:NPH_HAMIL: -8.4389608165E-04 +:NPH_ENTHALPY: -1.0368237065E+02 +:R: + 3.6306848821E-01 3.9617192510E-01 2.2992415665E-01 + 3.9041508380E+00 1.5357139826E+01 4.1086642440E+00 + 8.0049887158E+00 1.5199749372E+01 1.1117117214E-01 + 1.1388282230E+01 1.5361173492E+01 3.6344456295E+00 + 1.5099037869E-01 7.9294379599E+00 1.5366247466E+01 + 3.7416529381E+00 7.9260495011E+00 3.8149494346E+00 + 7.2929303514E+00 7.4270664162E+00 1.5236888207E-01 + 1.1554123508E+01 7.7957080141E+00 4.0430471986E+00 + 5.6495162441E-01 1.5184290651E+01 7.7555290301E+00 + 3.6475294168E+00 3.2307462475E-02 1.1246575734E+01 + 7.7092425689E+00 4.9785847313E-02 7.8228451463E+00 + 1.1607293999E+01 1.5188939582E+01 1.1778906183E+01 + 2.9277376613E-01 7.7147742071E+00 7.8951971088E+00 + 4.2367951674E+00 7.8993310917E+00 1.1506224039E+01 + 7.3328976246E+00 8.0210883763E+00 7.5469138832E+00 + 1.1555867176E+01 7.2776347023E+00 1.1512140440E+01 + 9.3021615136E-02 3.9391015446E+00 3.9451114361E+00 + 3.7262508249E+00 3.8757254420E+00 1.0481184707E-02 + 7.8592960644E+00 3.6387603412E+00 3.4197810860E+00 + 1.1392377061E+01 3.8186175166E+00 1.5227942306E+01 + 3.3718907142E-01 1.1447130019E+01 3.9257948923E+00 + 3.6213279896E+00 1.1587788796E+01 4.9660034388E-01 + 7.8575516051E+00 1.1721060122E+01 3.8537709635E+00 + 1.1063140717E+01 1.1529924298E+01 7.6057350934E-02 + 1.4319355574E-01 3.7130019065E+00 1.1260398636E+01 + 3.8248663778E+00 3.7026401095E+00 7.9868580212E+00 + 7.9432356979E+00 3.7758911087E+00 1.1561931154E+01 + 1.1386476825E+01 3.9746767057E+00 7.8430931735E+00 + 3.0339109132E-01 1.1549806676E+01 1.1531912561E+01 + 3.6924714201E+00 1.1265298293E+01 7.8521110586E+00 + 7.8723208750E+00 1.1772500566E+01 1.1734309152E+01 + 1.1652917663E+01 1.1557209050E+01 7.8489875826E+00 +:V: + -9.0624819706E-05 5.0414011466E-04 3.0299947363E-04 + 1.4765863501E-04 -3.6592094870E-05 3.1902938457E-04 + 3.3128583193E-04 -2.3214824849E-04 -3.0893189682E-04 + -1.5349484870E-04 -4.3389823218E-05 -2.3218327499E-04 + 1.9666357543E-04 2.7517971925E-04 -3.4152755805E-05 + -1.6242644343E-04 3.1571101764E-04 -3.5736258270E-05 + -4.7721184086E-04 -3.3535534802E-04 2.1308317059E-04 + 1.4545254740E-05 1.3698228031E-04 2.5255743960E-04 + 6.4573174060E-05 -2.7240751173E-04 3.4830336399E-05 + -1.8509990895E-04 3.2460159980E-05 -3.0600464694E-04 + 3.1395157322E-05 6.5415609536E-05 -2.3701525516E-04 + 1.2712568636E-04 -2.6239605965E-04 3.1567482960E-04 + 3.8247478249E-04 4.1590150468E-05 2.7354845519E-04 + 4.8224240991E-04 2.4006719267E-04 -4.3561313710E-05 + -4.3703211589E-04 4.0369765044E-04 -1.9681648465E-04 + 3.2697779422E-06 -5.7117437317E-04 -2.5176577361E-05 + 1.7226084863E-04 1.0700450812E-04 1.2063031247E-04 + -1.9246720611E-04 4.2006943820E-05 9.1131371665E-05 + 2.4307724271E-04 -2.9612695024E-04 -6.6824169861E-04 + -3.0448057148E-04 2.3056207482E-05 -2.1319320154E-04 + 1.7385750542E-04 -1.4365862907E-04 1.0166779539E-04 + -3.1551885898E-04 5.7781279214E-05 7.9707595645E-05 + 2.5782917126E-04 2.3142476575E-04 -1.0994923539E-04 + -7.8760287546E-04 7.5915823875E-06 1.5794750894E-04 + 2.1156340343E-04 -1.5872549191E-04 -4.5170593825E-04 + -9.6807813997E-05 -1.9807679434E-04 4.6574190079E-04 + 4.2352185996E-04 -8.1656311501E-05 -3.7839603280E-06 + -2.2266566642E-04 1.5679582148E-04 2.5527244455E-04 + 6.6073571893E-05 3.4539078205E-05 -1.1013119022E-04 + -3.6462880991E-04 -3.6230785403E-04 -4.7679749846E-04 + 3.6148364612E-04 3.1123010511E-04 1.8781248693E-04 + 1.0997854124E-04 1.7626674272E-05 2.9322506216E-04 +:F: + -8.9178925876E-04 -5.5501072821E-03 -1.4386566198E-03 + 1.0790702518E-02 -6.7774471868E-05 -6.2134039413E-03 + -1.8814453172E-02 5.7387543179E-03 -6.6615543970E-03 + 9.8682230066E-03 -1.3096344460E-03 9.8699312950E-03 + -1.8535535067E-03 -6.2231771448E-03 -4.0111286942E-04 + -3.5571876733E-03 1.3709313879E-03 1.0348747973E-04 + 1.0531756874E-02 4.6578292385E-03 -8.9792685894E-04 + 9.9197859809E-04 1.5791755503E-03 1.3520113069E-04 + -2.3803955392E-02 -7.9972182137E-04 -9.6276741391E-03 + 1.4960547248E-02 -4.6243396983E-03 1.8575375798E-02 + 1.4349077745E-03 1.1502874625E-03 3.4120112626E-03 + 8.1493388845E-03 -5.8767350499E-05 -2.9254784677E-03 + -5.3672305034E-03 2.0840124472E-03 3.1879730592E-04 + -5.4310243047E-03 -5.1902091564E-03 3.1980292395E-03 + 1.1115923018E-02 -6.6992846712E-03 -2.3032227828E-03 + -5.0742318659E-04 1.0095462296E-04 2.6994341238E-03 + 1.0961901814E-02 -1.3802358206E-03 -3.3584587482E-03 + -6.4770058770E-03 1.1354658582E-03 1.0627726409E-02 + 1.1165108913E-03 -4.6881924114E-03 -1.3199412367E-02 + -1.8259863401E-02 1.1420337875E-02 1.7414887257E-03 + 1.9928207251E-02 -3.3783160374E-03 2.2891408419E-03 + 7.1956182748E-04 6.5909196504E-04 1.5509947010E-02 + 1.5571056176E-03 -2.0621821196E-03 -1.5013459189E-02 + -1.6842281497E-02 7.5982787211E-04 4.9539597499E-03 + 1.1210361825E-03 3.9299295444E-03 -1.1798681589E-02 + -1.0380970803E-02 -3.4619043351E-04 6.0537627371E-03 + 1.4008115099E-02 9.7013181935E-04 -3.7397971826E-03 + -2.4201854637E-03 -3.7623872849E-03 1.1529449253E-02 + 9.5333906509E-03 5.9446077330E-03 -1.2492284988E-02 + -2.5854295383E-02 5.3764412155E-03 -2.5245680576E-03 + 1.5930719837E-02 9.3546856463E-04 -8.0378795764E-03 + -2.2587076713E-03 -1.6727273249E-03 9.6158294119E-03 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6447241196E+03 +:LATVEC_SCALE: + 1.5389395240E+01 1.5389395240E+01 1.5389395240E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 +:STRIO: + 1.0899874841E+00 2.1095032039E-02 -3.1513852199E-02 + 2.1095032039E-02 7.3046236449E-01 1.7021205712E-01 + -3.1513852199E-02 1.7021205712E-01 9.1104319170E-01 +:STRESS: + -1.4087970672E+00 -3.9086872025E-01 1.4352977055E+00 + -3.9086872025E-01 1.8640514420E+00 3.7875485988E-02 + 1.4352977055E+00 3.7875485988E-02 -1.3401233938E-01 +:CONSTRESS: + 3.4012948427E+00 8.0735588745E-01 -2.9028860864E+00 + 8.0735588745E-01 -3.9548856943E+00 2.6631151571E-01 + -2.9028860864E+00 2.6631151571E-01 5.5359085158E-01 +:TOTSTRESS: + -9.0251029147E-01 -3.9539213516E-01 1.4360745287E+00 + -3.9539213516E-01 2.8212966168E+00 -1.3397494457E-01 + 1.4360745287E+00 -1.3397494457E-01 4.9146467951E-01 +:PRESIO: 9.1049768008E-01 +:PRES: -1.0708067848E-01 +:CONPRES: 6.8647862492E-14 +:TOTPRES: 8.0341700161E-01 +:PRESIG: 9.3986857299E-01 +:MIND: +Al - Al: 4.6632668181E+00 +Si - Si: 4.7502345812E+00 +Al - Si: 4.7771479694E+00 diff --git a/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.refout b/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.refout new file mode 100644 index 00000000..b0fe02e4 --- /dev/null +++ b/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.refout @@ -0,0 +1,587 @@ +*************************************************************************** +* SPARC (version December 03, 2025) * +* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * +* Distributed under GNU General Public License 3 (GPL) * +* Start time: Mon Apr 6 12:09:24 2026 * +*************************************************************************** + Input parameters +*************************************************************************** +LATVEC_SCALE: 15 15 15 +LATVEC: +1.000000000000000 0.000000000000000 0.000000000000000 +0.000000000000000 1.000000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 +FD_GRID: 60 60 60 +FD_ORDER: 12 +BC: P P P +KPOINT_GRID: 1 1 1 +KPOINT_SHIFT: 0 0 0 +SPIN_TYP: 0 +ELEC_TEMP_TYPE: Fermi-Dirac +ELEC_TEMP: 1120 +EXCHANGE_CORRELATION: GGA_PBE +HUBBARD_FLAG: 0 +NSTATES: 76 +CHEB_DEGREE: 30 +CHEFSI_BOUND_FLAG: 0 +CALC_STRESS: 1 +TWTIME: 1E+09 +MD_FLAG: 1 +MD_METHOD: NPH +MD_TIMESTEP: 0.6 +MD_NSTEP: 10 +ION_VEL_DSTR: 2 +ION_VEL_DSTR_RAND: 0 +ION_TEMP: 1120 +NPH_SCALE_VECS: 1 2 3 +NPH_SCALE_CONSTRAINTS: 123 +NPH_ANGLES: 0 +NPH_BMASS: 0.1 +TARGET_STRESS: 0 0 0 0 0 0 GPa +RESTART_FLAG: 1 +MAXIT_SCF: 100 +MINIT_SCF: 2 +MAXIT_POISSON: 3000 +TOL_SCF: 5.00E-07 +POISSON_SOLVER: AAR +TOL_POISSON: 5.00E-09 +TOL_LANCZOS: 1.00E-02 +TOL_PSEUDOCHARGE: 5.00E-10 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +TOL_PRECOND: 6.25E-05 +PRECOND_KERKER_KTF: 1 +PRECOND_KERKER_THRESH: 0 +MIXING_PARAMETER: 1 +MIXING_HISTORY: 7 +PULAY_FREQUENCY: 1 +PULAY_RESTART: 0 +REFERENCE_CUTOFF: 0.5 +RHO_TRIGGER: 4 +NUM_CHEFSI: 1 +FIX_RAND: 0 +VERBOSITY: 1 +PRINT_FORCES: 1 +PRINT_ATOMS: 1 +PRINT_EIGEN: 0 +PRINT_DENSITY: 0 +PRINT_MDOUT: 1 +PRINT_VELS: 1 +PRINT_RESTART: 1 +PRINT_RESTART_FQ: 1 +PRINT_ENERGY_DENSITY: 0 +OUTPUT_FILE: Al16Si16_NPH_restart +*************************************************************************** + Cell +*************************************************************************** +Lattice vectors (Bohr): +15.000000000000000 0.000000000000000 0.000000000000000 +0.000000000000000 15.000000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 15.000000000000000 +Volume: 3.3750000000E+03 (Bohr^3) +Density: 2.6105618252E-01 (amu/Bohr^3), 2.9253624436E+00 (g/cc) +*************************************************************************** + Parallelization +*************************************************************************** +NP_SPIN_PARAL: 1 +NP_KPOINT_PARAL: 1 +NP_BAND_PARAL: 7 +NP_DOMAIN_PARAL: 5 1 1 +NP_DOMAIN_PHI_PARAL: 3 3 4 +EIG_SERIAL_MAXNS: 1500 +*************************************************************************** + Initialization +*************************************************************************** +Number of processors : 36 +Mesh spacing : 0.25 (Bohr) +Number of symmetry adapted k-points: 1 +Output printed to : Al16Si16_NPH_restart.out_01 +MD output printed to : Al16Si16_NPH_restart.aimd_01 +Total number of atom types : 2 +Total number of atoms : 32 +Total number of electrons : 112 +Atom type 1 (valence electrons) : Al 3 +Pseudopotential : ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +Atomic mass : 26.9815385 +Pseudocharge radii of atom type 1 : 7.50 7.50 7.50 (x, y, z dir) +Number of atoms of type 1 : 16 +Atom type 2 (valence electrons) : Si 4 +Pseudopotential : ../../../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 +Atomic mass : 28.085 +Pseudocharge radii of atom type 2 : 7.50 7.50 7.50 (x, y, z dir) +Number of atoms of type 2 : 16 +Estimated total memory usage : 946.98 MB +Estimated memory per processor : 26.30 MB +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.208153325 15.208153325 15.208153325 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.253469 (Bohr) +=================================================================== + Self Consistent Field (SCF#20) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2327922055E+00 1.230E-01 2.441 +2 -3.2423735729E+00 4.627E-02 0.623 +3 -3.2446994069E+00 2.234E-02 0.644 +4 -3.2454689970E+00 1.311E-02 0.661 +5 -3.2457081552E+00 7.038E-03 0.613 +6 -3.2457897182E+00 3.383E-03 0.654 +7 -3.2458183101E+00 1.614E-03 0.609 +8 -3.2458285096E+00 8.068E-04 0.649 +9 -3.2458321646E+00 3.131E-04 0.615 +10 -3.2458334868E+00 1.255E-04 0.639 +11 -3.2458339646E+00 5.919E-05 0.592 +12 -3.2458341382E+00 4.751E-05 0.609 +13 -3.2458342002E+00 1.510E-05 0.632 +14 -3.2458342228E+00 2.782E-05 0.591 +15 -3.2458342313E+00 5.614E-06 0.625 +16 -3.2458342343E+00 5.085E-06 0.631 +17 -3.2458342350E+00 8.879E-07 0.625 +18 -3.2458342356E+00 2.686E-06 0.632 +19 -3.2458342357E+00 1.228E-06 0.595 +20 -3.2458342359E+00 9.316E-07 0.627 +21 -3.2458342358E+00 1.950E-07 0.614 +Total number of SCF: 21 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2458342358E+00 (Ha/atom) +Total free energy : -1.0386669555E+02 (Ha) +Band structure energy : 5.1433650085E+00 (Ha) +Exchange correlation energy : -4.1882291900E+01 (Ha) +Self and correction energy : -1.6501196063E+02 (Ha) +-Entropy*kb*T : -2.9744461548E-02 (Ha) +Fermi level : 2.0512460107E-01 (Ha) +RMS force : 1.2179206127E-02 (Ha/Bohr) +Maximum force : 2.3680703673E-02 (Ha/Bohr) +Time for force calculation : 0.095 (sec) +Pressure : 1.6326537389E+00 (GPa) +Maximum stress : 3.4858326460E+00 (GPa) +Time for stress calculation : 0.185 (sec) +MD step time : 15.429 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.2267871868294 15.2267871868294 15.2267871868294 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.25378 (Bohr) +=================================================================== + Self Consistent Field (SCF#21) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2459443763E+00 1.448E-02 0.683 +2 -3.2458819323E+00 5.982E-03 0.659 +3 -3.2458768191E+00 2.458E-03 0.657 +4 -3.2458756386E+00 8.455E-04 0.644 +5 -3.2458754920E+00 1.176E-04 0.641 +6 -3.2458754897E+00 2.293E-05 0.639 +7 -3.2458754884E+00 1.033E-05 0.640 +8 -3.2458754897E+00 3.459E-06 0.638 +9 -3.2458754887E+00 1.036E-06 0.631 +10 -3.2458754892E+00 3.051E-07 0.574 +Total number of SCF: 10 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2458754892E+00 (Ha/atom) +Total free energy : -1.0386801565E+02 (Ha) +Band structure energy : 5.0388980208E+00 (Ha) +Exchange correlation energy : -4.1855610723E+01 (Ha) +Self and correction energy : -1.6501195543E+02 (Ha) +-Entropy*kb*T : -2.9068108940E-02 (Ha) +Fermi level : 2.0404375095E-01 (Ha) +RMS force : 1.2329953415E-02 (Ha/Bohr) +Maximum force : 2.4055052193E-02 (Ha/Bohr) +Time for force calculation : 0.094 (sec) +Pressure : 1.4395259827E+00 (GPa) +Maximum stress : 3.2401879380E+00 (GPa) +Time for stress calculation : 0.186 (sec) +MD step time : 6.797 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.2459084111316 15.2459084111316 15.2459084111316 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.254098 (Bohr) +=================================================================== + Self Consistent Field (SCF#22) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2459843171E+00 1.450E-02 0.674 +2 -3.2459212111E+00 5.860E-03 0.657 +3 -3.2459163989E+00 2.389E-03 0.648 +4 -3.2459153012E+00 8.459E-04 0.645 +5 -3.2459151545E+00 1.163E-04 0.641 +6 -3.2459151522E+00 2.241E-05 0.635 +7 -3.2459151508E+00 9.378E-06 0.627 +8 -3.2459151522E+00 3.371E-06 0.615 +9 -3.2459151512E+00 1.066E-06 0.623 +10 -3.2459151518E+00 3.059E-07 0.591 +Total number of SCF: 10 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2459151518E+00 (Ha/atom) +Total free energy : -1.0386928486E+02 (Ha) +Band structure energy : 4.9317287455E+00 (Ha) +Exchange correlation energy : -4.1828449216E+01 (Ha) +Self and correction energy : -1.6501195032E+02 (Ha) +-Entropy*kb*T : -2.8418860303E-02 (Ha) +Fermi level : 2.0293659052E-01 (Ha) +RMS force : 1.2469400521E-02 (Ha/Bohr) +Maximum force : 2.4479031348E-02 (Ha/Bohr) +Time for force calculation : 0.094 (sec) +Pressure : 1.2433884021E+00 (GPa) +Maximum stress : 2.9959074197E+00 (GPa) +Time for stress calculation : 0.182 (sec) +MD step time : 6.742 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.2654687930859 15.2654687930859 15.2654687930859 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.254424 (Bohr) +=================================================================== + Self Consistent Field (SCF#23) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2459501017E+00 1.819E-03 0.608 +2 -3.2459529044E+00 2.267E-04 0.637 +3 -3.2459529507E+00 1.016E-04 0.616 +4 -3.2459529554E+00 4.418E-05 0.632 +5 -3.2459529553E+00 2.321E-05 0.633 +6 -3.2459529554E+00 7.489E-06 0.612 +7 -3.2459529559E+00 3.922E-06 0.625 +8 -3.2459529558E+00 1.462E-06 0.621 +9 -3.2459529553E+00 4.265E-07 0.570 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2459529553E+00 (Ha/atom) +Total free energy : -1.0387049457E+02 (Ha) +Band structure energy : 4.8221296827E+00 (Ha) +Exchange correlation energy : -4.1800900428E+01 (Ha) +Self and correction energy : -1.6501194520E+02 (Ha) +-Entropy*kb*T : -2.7799205744E-02 (Ha) +Fermi level : 2.0180515789E-01 (Ha) +RMS force : 1.2597271087E-02 (Ha/Bohr) +Maximum force : 2.4871385464E-02 (Ha/Bohr) +Time for force calculation : 0.094 (sec) +Pressure : 1.0455640772E+00 (GPa) +Maximum stress : 2.7541777066E+00 (GPa) +Time for stress calculation : 0.182 (sec) +MD step time : 5.942 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.2854201470932 15.2854201470932 15.2854201470932 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.254757 (Bohr) +=================================================================== + Self Consistent Field (SCF#24) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2459857757E+00 1.841E-03 0.653 +2 -3.2459886543E+00 2.407E-04 0.632 +3 -3.2459887011E+00 1.384E-04 0.625 +4 -3.2459887021E+00 5.969E-05 0.617 +5 -3.2459887031E+00 2.419E-05 0.634 +6 -3.2459887034E+00 5.624E-06 0.614 +7 -3.2459887036E+00 3.744E-06 0.581 +8 -3.2459887036E+00 1.633E-06 0.621 +9 -3.2459887031E+00 5.297E-07 0.616 +10 -3.2459887033E+00 1.219E-07 0.594 +Total number of SCF: 10 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2459887033E+00 (Ha/atom) +Total free energy : -1.0387163850E+02 (Ha) +Band structure energy : 4.7103745707E+00 (Ha) +Exchange correlation energy : -4.1773057350E+01 (Ha) +Self and correction energy : -1.6501193999E+02 (Ha) +-Entropy*kb*T : -2.7211909278E-02 (Ha) +Fermi level : 2.0065145433E-01 (Ha) +RMS force : 1.2713425507E-02 (Ha/Bohr) +Maximum force : 2.5231119994E-02 (Ha/Bohr) +Time for force calculation : 0.094 (sec) +Pressure : 8.4736445891E-01 (GPa) +Maximum stress : 2.5161062334E+00 (GPa) +Time for stress calculation : 0.182 (sec) +MD step time : 6.575 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.3057146289023 15.3057146289023 15.3057146289023 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.255095 (Bohr) +=================================================================== + Self Consistent Field (SCF#25) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2381536781E+00 9.851E-01 0.672 +2 -3.2462456041E+00 7.013E-02 0.647 +3 -3.2461380979E+00 2.690E-02 0.654 +4 -3.2460511706E+00 1.269E-02 0.644 +5 -3.2460235461E+00 3.012E-03 0.636 +6 -3.2460223268E+00 1.036E-03 0.642 +7 -3.2460222002E+00 3.219E-04 0.633 +8 -3.2460222041E+00 1.059E-04 0.639 +9 -3.2460222092E+00 2.847E-05 0.637 +10 -3.2460222111E+00 1.221E-05 0.630 +11 -3.2460222110E+00 6.237E-06 0.623 +12 -3.2460222112E+00 2.041E-06 0.627 +13 -3.2460222116E+00 3.994E-07 0.615 +Total number of SCF: 13 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2460222116E+00 (Ha/atom) +Total free energy : -1.0387271077E+02 (Ha) +Band structure energy : 4.5967321473E+00 (Ha) +Exchange correlation energy : -4.1745010041E+01 (Ha) +Self and correction energy : -1.6501193470E+02 (Ha) +-Entropy*kb*T : -2.6660000971E-02 (Ha) +Fermi level : 1.9947741937E-01 (Ha) +RMS force : 1.2817962018E-02 (Ha/Bohr) +Maximum force : 2.5557573834E-02 (Ha/Bohr) +Time for force calculation : 0.095 (sec) +Pressure : 6.5003659899E-01 (GPa) +Maximum stress : 2.2826409404E+00 (GPa) +Time for stress calculation : 0.186 (sec) +MD step time : 8.702 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.3263050354704 15.3263050354704 15.3263050354704 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.255438 (Bohr) +=================================================================== + Self Consistent Field (SCF#26) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2460517347E+00 1.159E-03 0.651 +2 -3.2460533619E+00 2.256E-04 0.638 +3 -3.2460534073E+00 9.338E-05 0.634 +4 -3.2460534115E+00 3.881E-05 0.598 +5 -3.2460534124E+00 1.804E-05 0.630 +6 -3.2460534127E+00 6.569E-06 0.636 +7 -3.2460534128E+00 3.055E-06 0.626 +8 -3.2460534128E+00 8.042E-07 0.623 +9 -3.2460534128E+00 2.983E-07 0.583 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2460534128E+00 (Ha/atom) +Total free energy : -1.0387370921E+02 (Ha) +Band structure energy : 4.4814617131E+00 (Ha) +Exchange correlation energy : -4.1716847634E+01 (Ha) +Self and correction energy : -1.6501192918E+02 (Ha) +-Entropy*kb*T : -2.6146696011E-02 (Ha) +Fermi level : 1.9828499924E-01 (Ha) +RMS force : 1.2911420559E-02 (Ha/Bohr) +Maximum force : 2.5850205446E-02 (Ha/Bohr) +Time for force calculation : 0.095 (sec) +Pressure : 4.5478152269E-01 (GPa) +Maximum stress : 2.0545423266E+00 (GPa) +Time for stress calculation : 0.186 (sec) +MD step time : 6.007 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.3471450865833 15.3471450865833 15.3471450865833 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.255786 (Bohr) +=================================================================== + Self Consistent Field (SCF#27) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2460807143E+00 1.132E-03 0.654 +2 -3.2460823454E+00 2.186E-04 0.594 +3 -3.2460823901E+00 9.302E-05 0.637 +4 -3.2460823944E+00 4.059E-05 0.644 +5 -3.2460823950E+00 2.333E-05 0.594 +6 -3.2460823952E+00 7.153E-06 0.613 +7 -3.2460823955E+00 3.192E-06 0.584 +8 -3.2460823955E+00 8.745E-07 0.628 +9 -3.2460823955E+00 2.880E-07 0.626 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2460823955E+00 (Ha/atom) +Total free energy : -1.0387463666E+02 (Ha) +Band structure energy : 4.3648186936E+00 (Ha) +Exchange correlation energy : -4.1688657526E+01 (Ha) +Self and correction energy : -1.6501192371E+02 (Ha) +-Entropy*kb*T : -2.5675213178E-02 (Ha) +Fermi level : 1.9707611830E-01 (Ha) +RMS force : 1.2994131423E-02 (Ha/Bohr) +Maximum force : 2.6109260362E-02 (Ha/Bohr) +Time for force calculation : 0.095 (sec) +Pressure : 2.6282427442E-01 (GPa) +Maximum stress : 1.8325549884E+00 (GPa) +Time for stress calculation : 0.187 (sec) +MD step time : 6.008 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.3681897040043 15.3681897040043 15.3681897040043 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.256136 (Bohr) +=================================================================== + Self Consistent Field (SCF#28) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2461061821E+00 1.889E-03 0.645 +2 -3.2461092528E+00 2.340E-04 0.632 +3 -3.2461092994E+00 9.512E-05 0.649 +4 -3.2461093046E+00 3.668E-05 0.634 +5 -3.2461093050E+00 1.379E-05 0.643 +6 -3.2461093052E+00 6.687E-06 0.595 +7 -3.2461093058E+00 3.029E-06 0.627 +8 -3.2461093057E+00 7.953E-07 0.616 +9 -3.2461093055E+00 2.458E-07 0.626 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2461093055E+00 (Ha/atom) +Total free energy : -1.0387549778E+02 (Ha) +Band structure energy : 4.2470442033E+00 (Ha) +Exchange correlation energy : -4.1660522119E+01 (Ha) +Self and correction energy : -1.6501191891E+02 (Ha) +-Entropy*kb*T : -2.5248777696E-02 (Ha) +Fermi level : 1.9585258667E-01 (Ha) +RMS force : 1.3066869586E-02 (Ha/Bohr) +Maximum force : 2.6335054848E-02 (Ha/Bohr) +Time for force calculation : 0.095 (sec) +Pressure : 7.5193888356E-02 (GPa) +Maximum stress : 1.7832091519E+00 (GPa) +Time for stress calculation : 0.187 (sec) +MD step time : 6.054 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.3893952396143 15.3893952396143 15.3893952396143 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.25649 (Bohr) +=================================================================== + Self Consistent Field (SCF#29) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2461310007E+00 1.910E-03 0.666 +2 -3.2461341895E+00 2.328E-04 0.649 +3 -3.2461342376E+00 1.105E-04 0.650 +4 -3.2461342407E+00 4.780E-05 0.590 +5 -3.2461342412E+00 2.451E-05 0.643 +6 -3.2461342416E+00 6.041E-06 0.640 +7 -3.2461342420E+00 3.767E-06 0.630 +8 -3.2461342418E+00 1.432E-06 0.592 +9 -3.2461342413E+00 4.498E-07 0.603 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2461342413E+00 (Ha/atom) +Total free energy : -1.0387629572E+02 (Ha) +Band structure energy : 4.1283777017E+00 (Ha) +Exchange correlation energy : -4.1632522208E+01 (Ha) +Self and correction energy : -1.6501191447E+02 (Ha) +-Entropy*kb*T : -2.4870468440E-02 (Ha) +Fermi level : 1.9461625771E-01 (Ha) +RMS force : 1.3130492014E-02 (Ha/Bohr) +Maximum force : 2.6527799640E-02 (Ha/Bohr) +Time for force calculation : 0.088 (sec) +Pressure : -1.0708067848E-01 (GPa) +Maximum stress : 1.8640514420E+00 (GPa) +Time for stress calculation : 0.168 (sec) +MD step time : 6.019 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 15.4107196966269 15.4107196966269 15.4107196966269 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing : 0.256845 (Bohr) +=================================================================== + Self Consistent Field (SCF#30) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -3.2461538629E+00 1.943E-03 0.654 +2 -3.2461571398E+00 2.384E-04 0.630 +3 -3.2461571871E+00 9.793E-05 0.647 +4 -3.2461571915E+00 3.784E-05 0.643 +5 -3.2461571919E+00 1.582E-05 0.629 +6 -3.2461571920E+00 6.510E-06 0.630 +7 -3.2461571927E+00 3.037E-06 0.629 +8 -3.2461571924E+00 8.079E-07 0.622 +9 -3.2461571925E+00 2.182E-07 0.618 +Total number of SCF: 9 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -3.2461571925E+00 (Ha/atom) +Total free energy : -1.0387703016E+02 (Ha) +Band structure energy : 4.0090558868E+00 (Ha) +Exchange correlation energy : -4.1604736620E+01 (Ha) +Self and correction energy : -1.6501191041E+02 (Ha) +-Entropy*kb*T : -2.4542988920E-02 (Ha) +Fermi level : 1.9336902026E-01 (Ha) +RMS force : 1.3185952855E-02 (Ha/Bohr) +Maximum force : 2.6687323100E-02 (Ha/Bohr) +Time for force calculation : 0.088 (sec) +Pressure : -2.8300465674E-01 (GPa) +Maximum stress : 1.9470955163E+00 (GPa) +Time for stress calculation : 0.168 (sec) +*************************************************************************** + Timing info +*************************************************************************** +Total walltime : 80.541 sec +___________________________________________________________________________ + +*************************************************************************** +* Material Physics & Mechanics Group, Georgia Tech * +* PI: Phanish Suryanarayana * +* List of contributors: See the documentation * +* Citation: See README.md or the documentation for details * +* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * +* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * +*************************************************************************** + diff --git a/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.restart b/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.restart new file mode 100644 index 00000000..8b56da7e --- /dev/null +++ b/tests/Al16Si16_NPH_restart/standard/Al16Si16_NPH_restart.restart @@ -0,0 +1,128 @@ +:MDSTEP: 20 +:R(Bohr): + 3.7823458916E-01 2.7610460926E-01 1.5878927437E-01 + 3.8306033205E+00 1.5184573827E+01 3.9859739488E+00 + 7.8281895558E+00 1.5074962428E+01 1.7561114565E-01 + 1.1293120965E+01 1.5189314181E+01 3.6481833123E+00 + 1.0435468268E-01 7.7713558143E+00 1.5192718538E+01 + 3.7321459897E+00 7.7627920119E+00 3.7783484433E+00 + 7.3190025969E+00 7.4168484355E+00 1.0284005934E-01 + 1.1415067004E+01 7.6738853814E+00 3.9386418353E+00 + 5.3229704039E-01 1.5066232122E+01 7.6519055296E+00 + 3.6530720897E+00 2.2840542397E-02 1.1191061767E+01 + 7.6121710804E+00 3.4847066886E-02 7.7850414043E+00 + 1.1445811536E+01 1.5068855172E+01 1.1568537402E+01 + 2.0175776191E-01 7.6157878874E+00 7.7412657720E+00 + 4.0760847909E+00 7.7499371772E+00 1.1381601394E+01 + 7.3492754612E+00 7.8332359584E+00 7.5012957501E+00 + 1.1418435117E+01 7.3193800096E+00 1.1383498648E+01 + 5.8236045647E-02 3.8678818278E+00 3.8703400677E+00 + 3.7226155939E+00 3.8210906346E+00 1.5203447282E+01 + 7.7130823852E+00 3.6601846015E+00 3.5222899517E+00 + 1.1317786229E+01 3.7738445375E+00 1.5096979981E+01 + 3.0428421164E-01 1.1342899268E+01 3.8577699134E+00 + 3.6493300723E+00 1.1438546793E+01 4.8043339327E-01 + 7.7087007769E+00 1.1530410366E+01 3.8252851649E+00 + 1.1099726003E+01 1.1393437716E+01 4.2518679669E-02 + 9.5144068216E-02 3.7066129992E+00 1.1222956160E+01 + 3.7963159924E+00 3.7030104254E+00 7.7924390927E+00 + 7.7618077996E+00 3.7504561440E+00 1.1424674305E+01 + 1.1301118907E+01 3.8912491122E+00 7.6990941122E+00 + 2.8980766672E-01 1.1408578417E+01 1.1414388909E+01 + 3.7181576669E+00 1.1215586629E+01 7.8651423642E+00 + 7.7071115916E+00 1.1564668770E+01 1.1550084397E+01 + 1.1489511031E+01 1.1416565408E+01 7.6960563643E+00 +:V(Bohr/atu): + -8.1778023086E-05 5.3559952164E-04 3.1337523565E-04 + 9.8474247471E-05 -3.9092155991E-05 3.5055599313E-04 + 4.1017819235E-04 -2.5470800261E-04 -2.8216002883E-04 + -1.9751070468E-04 -3.8062432505E-05 -2.7725398738E-04 + 2.0727712557E-04 3.0905000069E-04 -3.2721376966E-05 + -1.4857054711E-04 3.1420219970E-04 -4.0814012455E-05 + -5.3309707411E-04 -3.6085142672E-04 2.1504594259E-04 + 1.3435491358E-05 1.3424435214E-04 2.6105244271E-04 + 1.7206218705E-04 -2.7631284727E-04 7.5543155711E-05 + -2.5238382734E-04 4.7416841562E-05 -3.8601697276E-04 + 2.4628122118E-05 6.5406442068E-05 -2.5061381322E-04 + 9.6962504848E-05 -2.6827093178E-04 3.2792498328E-04 + 4.0375062409E-04 3.0841797734E-05 2.7511524597E-04 + 5.1843831823E-04 2.6893794107E-04 -5.2492535478E-05 + -4.8719968061E-04 4.3746304758E-04 -1.9489295385E-04 + 1.0870761229E-05 -5.7538514507E-04 -3.7588206752E-05 + 1.3215069613E-04 1.1835677014E-04 1.3342591435E-04 + -1.7068148402E-04 3.9552959042E-05 4.1382429227E-05 + 2.3831707436E-04 -2.8412077111E-04 -6.1370302211E-04 + -2.3045121903E-04 -2.5824850976E-05 -2.2237576658E-04 + 8.1358082286E-05 -1.3194229631E-04 9.5638146684E-05 + -3.1927857785E-04 5.8193443871E-05 1.0080123268E-05 + 2.4523672380E-04 2.4221824291E-04 -3.6574808048E-05 + -7.0617259286E-04 -4.8592063356E-06 1.3279896936E-04 + 2.0351515122E-04 -1.7806773630E-04 -4.0289516309E-04 + -4.9039917024E-05 -1.9748123884E-04 4.3192612914E-04 + 3.6529455572E-04 -9.1571810080E-05 1.5168370725E-05 + -2.1653212277E-04 1.7225871185E-04 2.0923472768E-04 + 2.0794793994E-05 1.3342609930E-05 -5.0100417993E-05 + -2.5438583406E-04 -3.8228623268E-04 -4.7467259813E-04 + 2.8500067023E-04 3.1242420638E-04 2.3002281645E-04 + 1.2937637624E-04 2.2312545903E-05 2.4695993759E-04 +:Pm_ion: + -6.1024694397E+01 3.9967702683E+02 2.3384801033E+02 + 7.3483811801E+01 -2.9171491101E+01 2.6159317067E+02 + 3.0608466544E+02 -1.9006913390E+02 -2.1055448495E+02 + -1.4738715780E+02 -2.8403087089E+01 -2.0689348082E+02 + 1.5467509199E+02 2.3062041773E+02 -2.4417465161E+01 + -1.1086685508E+02 2.3446511046E+02 -3.0456381106E+01 + -3.9780964132E+02 -2.6927586663E+02 1.6047236694E+02 + 1.0025881322E+01 1.0017630966E+02 1.9480350511E+02 + 1.2839687224E+02 -2.0619117981E+02 5.6372088944E+01 + -1.8833477936E+02 3.5383568304E+01 -2.8805499211E+02 + 1.8378087035E+01 4.8807833549E+01 -1.8701395297E+02 + 7.2355713712E+01 -2.0019011233E+02 2.4470537603E+02 + 3.0128826203E+02 2.3014878697E+01 2.0529750140E+02 + 3.8687093109E+02 2.0068785043E+02 -3.9171171114E+01 + -3.6355992108E+02 3.2644526954E+02 -1.4543373024E+02 + 8.1120190587E+00 -4.2936599973E+02 -2.8049208619E+01 + 1.0264698067E+02 9.1932660609E+01 1.0363749608E+02 + -1.3257545745E+02 3.0722439921E+01 3.2143466039E+01 + 1.8511085331E+02 -2.2068850301E+02 -4.7668884156E+02 + -1.7900111402E+02 -2.0059243399E+01 -1.7272857187E+02 + 6.3194230106E+01 -1.0248510780E+02 7.4286154230E+01 + -2.4799704405E+02 4.5201285224E+01 7.8296539373E+00 + 1.9048563485E+02 1.8814105432E+02 -2.8409185307E+01 + -5.4851383015E+02 -3.7743490835E+00 1.0315052164E+02 + 1.5807874196E+02 -1.3831266896E+02 -3.1294554800E+02 + -3.8091357536E+01 -1.5339194950E+02 3.3549511526E+02 + 2.8373958139E+02 -7.1127660275E+01 1.1781908853E+01 + -1.6818956897E+02 1.3380055636E+02 1.6252137656E+02 + 1.6152187462E+01 1.0363763973E+01 -3.8915093057E+01 + -1.9759213199E+02 -2.9693772857E+02 -3.6869808811E+02 + 2.2137195751E+02 2.4267296664E+02 1.7866835580E+02 + 1.0049205022E+02 1.7331088939E+01 1.9182412718E+02 +:NPH_BMASS: 0.1 +:NPH_INIT_Hamiltonian: -103.681526754895 +:KE: 0.166849310856701 +:Kbaro: 0.016949643288971 +:Ubaro: 0 +:kinetic_stress: + 0.000277120701010979 -9.25264571565886e-07 4.01244760454559e-06 + -9.25264571565886e-07 0.000212554417024622 4.59493523128306e-05 + 4.01244760454559e-06 4.59493523128306e-05 0.000233437168299877 +:Pm_metric_tensor: + 0.518927481076437 0.000980517563512018 -0.00372932063664148 + 0.000980517563512018 0.502090286248635 0.000421216548679229 + -0.00372932063664148 0.000421216548679229 0.516122550885578 +:LATVEC_SCALE: 1.5208153325E+01 1.5208153325E+01 1.5208153325E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:INITIAL_ANGLES: 9.0000000000E+01 9.0000000000E+01 9.0000000000E+01 +:ROTATION_MATRIX: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:TTHRMI(K): 1120 +:EXTERNAL_PRESSURE: 0 +:EXTERNAL_STRESS: 0 0 0 0 0 0 GPa +:TEL(K): 1.1200000000E+03 +:TIO(K): 1.1330504360E+03 diff --git a/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.inpt b/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.inpt index 3e2e39a6..741e4db9 100644 --- a/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.inpt +++ b/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.inpt @@ -4,7 +4,7 @@ LATVEC: 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 -MESH_SPACING: 0.30 +MESH_SPACING: 0.2 BC: P P P KPOINT_GRID: 1 1 1 # SPIN_TYP: 1 @@ -28,7 +28,7 @@ MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whichev #TWTIME: 1400 RESTART_FLAG: 1 # 1 = restart MD from .restart file if present, 0 = start new #ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) -TARGET_PRESSURE: 0 GPa +EXTERNAL_PRESSURE: 0 GPa NPT_NP_QMASS: 500.0 NPT_NP_BMASS: 0.1 NPT_SCALE_CONSTRAINTS: 123 diff --git a/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.refaimd b/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.refaimd index a2fc4c46..1ae6e637 100644 --- a/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.refaimd +++ b/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.refaimd @@ -14,12 +14,21 @@ :Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom :Desc_UEN: Internal energy. Unit=Ha/atom :Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom -:Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 -:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom +:Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree +:Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 +:Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 +:Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during NPT_NP ensemble (has same magnitude as initial LatVec). Unit = Bohr +:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha +:Desc_SNOSE[0]: Position variable of the thermostat +:Desc_SNOSE[1]: Velocity variable of the thermostat :Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) :Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) :Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa :Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa +:Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa +:Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa :Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa where N = number of particles, k = Boltzmann constant, V = volume :Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu @@ -27,1273 +36,1493 @@ :Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr -:MDSTEP: 31 -:MDTM: 1.53 + + +:MDSTEP: 21 +:MDTM: 46.09 :TWIST: 0 :TEL: 1120 -:TIO: 1122.82502374911 -:TEN: -3.2409821870E+00 -:KEN: 5.1669859377E-03 -:KENIG: 5.3336629034E-03 -:FEN: -3.2461491729E+00 -:UEN: -3.2453877801E+00 -:TSEN: -7.6139275865E-04 -:NPT_NP_HAMIL: -2.7893573389E-05 +:TIO: 1118.7172572831 +:TEN: -3.2406819691E+00 +:KEN: 5.1480829287E-03 +:KENIG: 5.3141501199E-03 +:FEN: -3.2458300520E+00 +:UEN: -3.2449001593E+00 +:TSEN: -9.2989274927E-04 +:NPT_NP_HAMIL: -3.9847915075E-05 +:SNOSE[0]: 1.0062076146E+00 +:SNOSE[1]: 5.2714356748E-05 :R: - 3.5936467593E-01 4.0594591719E-01 2.3642953591E-01 - 3.8962368288E+00 1.5309956685E+01 4.1026622884E+00 - 7.9872147570E+00 1.5148735220E+01 1.0342990934E-01 - 1.1350842434E+01 1.5313565616E+01 3.6185204470E+00 - 1.5491789015E-01 7.9110401500E+00 1.5318963792E+01 - 3.7263405552E+00 7.9084472542E+00 3.8026566678E+00 - 7.2610478441E+00 7.3973139123E+00 1.5693124245E-01 - 1.1519261043E+01 7.7751236378E+00 4.0358003814E+00 - 5.6273813057E-01 1.5132079365E+01 7.7323409585E+00 - 3.6330958353E+00 3.2935570167E-02 1.1206750166E+01 - 7.6871569822E+00 5.0782488610E-02 7.7935132985E+00 - 1.1575388204E+01 1.5137289247E+01 1.1749934305E+01 - 3.0037437057E-01 7.6920681398E+00 7.8775049726E+00 - 4.2340379888E+00 7.8802471762E+00 1.1470557873E+01 - 7.3018094988E+00 8.0053724314E+00 7.5197996182E+00 - 1.1520374623E+01 7.2429441121E+00 1.1476618486E+01 - 9.6758094714E-02 3.9294503688E+00 3.9353943547E+00 - 3.7101787493E+00 3.8649880792E+00 1.3052780940E-02 - 7.8411623470E+00 3.6210265668E+00 3.3940543490E+00 - 1.1350539042E+01 3.8077117768E+00 1.5177307846E+01 - 3.3982559823E-01 1.1409533785E+01 3.9161691270E+00 - 3.6033988666E+00 1.1554270814E+01 4.9649274264E-01 - 7.8397115906E+00 1.1690658659E+01 3.8394665080E+00 - 1.1011560501E+01 1.1494743725E+01 7.9975942983E-02 - 1.4787982722E-01 3.6983548898E+00 1.1215758167E+01 - 3.8108766073E+00 3.6873897226E+00 7.9737160017E+00 - 7.9291313374E+00 3.7626888813E+00 1.1526462327E+01 - 1.1346748605E+01 3.9656895842E+00 7.8254711952E+00 - 3.0403458226E-01 1.1515608251E+01 1.1494431296E+01 - 3.6731883330E+00 1.1223577645E+01 7.8171300645E+00 - 7.8567887966E+00 1.1743314907E+01 1.1702311705E+01 - 1.1619743913E+01 1.1522755950E+01 7.8317991285E+00 + 3.7827678095E-01 2.7577317121E-01 1.5858841243E-01 + 3.8307092758E+00 1.5185075920E+01 3.9858789816E+00 + 7.8281950745E+00 1.5075590422E+01 1.7580512791E-01 + 1.1293584727E+01 1.5189817555E+01 3.6484629030E+00 + 1.0423254155E-01 7.7714209934E+00 1.5193223522E+01 + 3.7323504950E+00 7.7628577620E+00 3.7785006822E+00 + 7.3195779770E+00 7.4172989322E+00 1.0272035466E-01 + 1.1415408068E+01 7.6740588015E+00 3.9386119308E+00 + 5.3218152134E-01 1.5066872252E+01 7.6521167923E+00 + 3.6533494467E+00 2.2809980133E-02 1.1191648009E+01 + 7.6123834266E+00 3.4814175792E-02 7.7854454836E+00 + 1.1446113810E+01 1.5069497216E+01 1.1568706253E+01 + 2.0151606134E-01 7.6160152243E+00 7.7413474673E+00 + 4.0758640745E+00 7.7500310576E+00 1.1381970516E+01 + 7.3498146660E+00 7.8332129497E+00 7.5016316543E+00 + 1.1418802929E+01 7.3199554066E+00 1.1383882257E+01 + 5.8171533604E-02 3.8679323084E+00 3.8703840200E+00 + 3.7228341056E+00 3.8211981505E+00 1.5203912179E+01 + 7.7131780041E+00 3.6604663633E+00 3.5227608437E+00 + 1.1318248080E+01 3.7739798741E+00 1.5097588160E+01 + 3.0427805990E-01 1.1343323341E+01 3.8578526588E+00 + 3.6496386977E+00 1.1438862024E+01 4.8044956361E-01 + 7.7088052967E+00 1.1530637893E+01 3.8254282582E+00 + 1.1100483209E+01 1.1393824361E+01 4.2438955812E-02 + 9.5032872030E-02 3.7068366927E+00 1.1223535356E+01 + 3.7964592693E+00 3.7032500767E+00 7.7924350678E+00 + 7.7618551619E+00 3.7506323701E+00 1.1425026861E+01 + 1.1301612855E+01 3.8912710805E+00 7.6992345023E+00 + 2.8982660840E-01 1.1408931344E+01 1.1414781652E+01 + 3.7184028262E+00 1.1216161807E+01 7.8656691969E+00 + 7.7072060211E+00 1.1564860043E+01 1.1550325002E+01 + 1.1489801633E+01 1.1416912387E+01 7.6961435808E+00 :V: - -9.1904629056E-05 4.9514354787E-04 3.0086202637E-04 - 1.5037285528E-04 -3.4915479047E-05 3.1072181814E-04 - 3.1843751864E-04 -2.2618449696E-04 -3.0925991621E-04 - -1.4640647169E-04 -4.3087874322E-05 -2.2540287130E-04 - 1.9314717378E-04 2.6788480945E-04 -3.3310441673E-05 - -1.6235750138E-04 3.0918102363E-04 -3.4616724961E-05 - -4.6443220288E-04 -3.2832305286E-04 2.1125277579E-04 - 1.3940664123E-05 1.3561872161E-04 2.4694826814E-04 - 4.9684711560E-05 -2.6892361440E-04 2.9825882309E-05 - -1.7563198698E-04 3.0678209229E-05 -2.9264352711E-04 - 3.4311308449E-05 6.3225649422E-05 -2.3417500880E-04 - 1.2950214945E-04 -2.5748599518E-04 3.0960346119E-04 - 3.7556868504E-04 4.0293453514E-05 2.7066644492E-04 - 4.7254021716E-04 2.3358683802E-04 -4.1489144345E-05 - -4.2439820806E-04 3.9531007735E-04 -1.9371167539E-04 - 8.4224698345E-07 -5.6230006313E-04 -2.4195254307E-05 - 1.7291881848E-04 1.0503554396E-04 1.1671111525E-04 - -1.9332504197E-04 4.1925353220E-05 9.4353681538E-05 - 2.4098683558E-04 -2.9284063101E-04 -6.6317230735E-04 - -3.0534412883E-04 2.5968473960E-05 -2.0840165286E-04 - 1.7394998648E-04 -1.4080474478E-04 1.0102942658E-04 - -3.1018634568E-04 5.8775509685E-05 7.9861821257E-05 - 2.5565540089E-04 2.2755014451E-04 -1.1183615476E-04 - -7.8185701501E-04 5.0958368718E-06 1.5952043355E-04 - 2.1041758090E-04 -1.5502854208E-04 -4.4931629734E-04 - -9.7660056909E-05 -1.9319936837E-04 4.6364956872E-04 - 4.2235750588E-04 -7.9834020706E-05 -5.8956101541E-06 - -2.2114538913E-04 1.5201438574E-04 2.5601305690E-04 - 6.7237228861E-05 3.5614677644E-05 -1.1110846709E-04 - -3.6425416277E-04 -3.5334285512E-04 -4.7333993410E-04 - 3.6102997854E-04 3.0522801405E-04 1.8045455902E-04 - 1.0673696975E-04 1.7951266590E-05 2.9183704769E-04 + -8.2023109578E-05 5.2987427688E-04 3.1038124602E-04 + 1.0047177040E-04 -3.8537917130E-05 3.4625890665E-04 + 4.0353889944E-04 -2.5186668416E-04 -2.8131432272E-04 + -1.9396106314E-04 -3.8005180500E-05 -2.7295610875E-04 + 2.0522473456E-04 3.0487304142E-04 -3.2543082540E-05 + -1.4809334743E-04 3.1177072444E-04 -4.0039072196E-05 + -5.2600765477E-04 -3.5679912163E-04 2.1357460096E-04 + 1.3155335626E-05 1.3322987966E-04 2.5838138578E-04 + 1.6526872186E-04 -2.7379888716E-04 7.3209378812E-05 + -2.4719789937E-04 4.6635648035E-05 -3.7939412462E-04 + 2.4796496402E-05 6.4716212818E-05 -2.4831023932E-04 + 9.7507859248E-05 -2.6574235107E-04 3.2504177428E-04 + 3.9990707498E-04 3.1195018833E-05 2.7293853377E-04 + 5.1222206231E-04 2.6535467245E-04 -5.2041554324E-05 + -4.8116302395E-04 4.3243357709E-04 -1.9323892978E-04 + 1.0191925623E-05 -5.7091526139E-04 -3.6721012761E-05 + 1.3289173972E-04 1.1667208482E-04 1.3193312047E-04 + -1.7030718608E-04 3.9300662281E-05 4.3838752155E-05 + 2.3698011842E-04 -2.8229159233E-04 -6.1204035682E-04 + -2.3245315324E-04 -2.3242205451E-05 -2.2027203239E-04 + 8.5858518170E-05 -1.3149241786E-04 9.5017676434E-05 + -3.1685550806E-04 5.7563951944E-05 1.3717912650E-05 + 2.4456718740E-04 2.3987022786E-04 -4.0567644186E-05 + -7.0579892314E-04 -3.7070971137E-06 1.3347318803E-04 + 2.0267255749E-04 -1.7572793891E-04 -4.0241177631E-04 + -5.1247282547E-05 -1.9601364326E-04 4.3103262739E-04 + 3.6558730365E-04 -9.0157069876E-05 1.3930969633E-05 + -2.1511327359E-04 1.7032854027E-04 2.0980921910E-04 + 2.3300141424E-05 1.4092598328E-05 -5.3164334627E-05 + -2.5817481366E-04 -3.7877112082E-04 -4.7084049959E-04 + 2.8729582014E-04 3.0987673116E-04 2.2578825101E-04 + 1.2693131415E-04 2.2027031142E-05 2.4786976887E-04 :F: - -9.7997231575E-04 -6.1041334089E-03 -1.4039490917E-03 - 1.0897370252E-02 1.0125099559E-04 -6.7679054584E-03 - -2.0464104168E-02 6.6781300906E-03 -7.0120553945E-03 - 1.0696535968E-02 -1.2646932245E-03 1.0508500493E-02 - -2.1977544185E-03 -6.7116043681E-03 -3.9447067016E-04 - -3.5082437551E-03 6.0293279707E-04 1.1066508663E-04 - 1.1414794719E-02 5.2271341619E-03 -1.1293264910E-03 - 1.0538113076E-03 1.6242892027E-03 -7.3282983077E-05 - -2.5234726496E-02 -7.3553700958E-04 -1.0227217534E-02 - 1.5875164836E-02 -5.1631147590E-03 1.9979831662E-02 - 1.8618154741E-03 1.0589390711E-03 3.6775559588E-03 - 8.8242508569E-03 3.3232144513E-04 -3.5546387327E-03 - -6.2101739225E-03 1.6586191776E-03 2.3949785218E-04 - -5.7497004500E-03 -5.5951672732E-03 3.6920724695E-03 - 1.2440113120E-02 -7.3328609944E-03 -2.3533536900E-03 - -5.7002443360E-04 1.1055906318E-03 2.8598066323E-03 - 1.1134783272E-02 -1.3316512562E-03 -3.7223473156E-03 - -6.7599974492E-03 1.2462051430E-03 1.0677035657E-02 - 7.8321058590E-04 -4.5815411963E-03 -1.2443858128E-02 - -1.8080869172E-02 1.1554970455E-02 2.1546591762E-03 - 1.8867353536E-02 -2.9601344748E-03 2.3230931020E-03 - 1.3446911503E-03 1.0258031131E-03 1.4841350236E-02 - 1.0239878493E-03 -2.3799094880E-03 -1.4414281731E-02 - -1.5308453089E-02 -5.1069015065E-04 5.0160763483E-03 - 6.2031223392E-04 4.0814327821E-03 -1.1322721919E-02 - -9.8757405004E-03 3.1974283781E-04 5.3814566968E-03 - 1.3582482030E-02 8.8500255723E-04 -3.8812619790E-03 - -2.4205180193E-03 -4.4491715674E-03 1.1499448940E-02 - 9.2305453441E-03 6.1475795532E-03 -1.2014334817E-02 - -2.5266981281E-02 6.7826108604E-03 -2.6372037774E-03 - 1.5227731845E-02 3.9387528507E-04 -8.7693020286E-03 - -2.2516949121E-03 -1.7062209898E-03 9.1604614304E-03 -:LATVEC_SCALE: 1.5342670739E+01 1.5342670739E+01 1.5342670739E+01 + -3.3290128841E-03 -4.2874493141E-03 -1.0278838661E-03 + 1.0248643914E-02 8.6468877635E-04 -4.8691368227E-03 + -1.2188297270E-02 2.7303505071E-03 -6.1835924852E-03 + 7.4337914817E-03 -1.0477813687E-03 7.4928832469E-03 + -1.2192018145E-03 -6.0154415728E-03 -4.3430355756E-04 + -2.9968099269E-03 9.3159155606E-04 1.5425620235E-03 + 9.5064672692E-03 3.7667363720E-03 1.1682414755E-03 + -3.3793071240E-04 3.5331334681E-04 -1.8318515186E-03 + -2.0170167128E-02 6.4572465945E-04 -6.9039648110E-03 + 1.1752336025E-02 -1.5436922366E-03 1.2871562521E-02 + 1.6014618069E-03 -5.9497834489E-04 8.2516787365E-04 + 5.3002987551E-03 9.1478528509E-04 -4.0230499720E-04 + -1.4669200764E-03 2.3479220544E-03 6.1500034928E-04 + -6.3697328286E-03 -5.1137687688E-03 4.4350330394E-04 + 7.0751149548E-03 -4.8933884853E-03 1.9539809811E-04 + -2.3968041101E-03 -1.5364508087E-03 2.2607224525E-03 + 7.3037399165E-03 -2.7149574076E-03 -1.5265111556E-03 + -4.2912184637E-03 2.8962728679E-04 1.1180642848E-02 + 2.7940050229E-03 -2.3283269904E-03 -1.4240073346E-02 + -1.5479729731E-02 9.5415934075E-03 1.0017372596E-03 + 2.0424074853E-02 -2.4610893622E-03 6.8499287759E-04 + -1.1475423953E-03 -4.3688556704E-04 1.4828196664E-02 + 5.4288482958E-03 -1.2425154210E-03 -1.7048887457E-02 + -2.2238255564E-02 4.1481383967E-03 7.0840786187E-03 + 3.4271819470E-03 3.3547686279E-03 -1.1605697328E-02 + -1.0526321391E-02 -8.8967901710E-04 1.0988665205E-02 + 1.3394960571E-02 2.4956630942E-03 -4.3713870041E-03 + -1.7173026238E-03 -1.9946108980E-03 9.2587056256E-03 + 1.0465275300E-02 3.4836353547E-03 -1.3918205056E-02 + -2.3547106036E-02 1.2383537807E-03 -8.7830821716E-04 + 1.8605151946E-02 3.3524680333E-04 -9.2286113339E-03 + -5.3389991038E-03 -3.4112374573E-04 1.2028658514E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5177975127E+03 +:LATVEC_SCALE: + 1.5208636471E+01 1.5208636471E+01 1.5208636471E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 :STRIO: - -1.0720305808E+00 -2.2532307738E-02 3.7269796278E-02 - -2.2532307738E-02 -7.0906497347E-01 -1.6822233848E-01 - 3.7269796278E-02 -1.6822233848E-01 -8.9978472549E-01 + 1.0581190747E+00 -2.2602430269E-03 1.2304741013E-02 + -2.2602430269E-03 8.0626856262E-01 1.7489096668E-01 + 1.2304741013E-02 1.7489096668E-01 8.9118797461E-01 :STRESS: - -2.2928032066E+00 -4.0093682958E-01 1.5582828152E+00 - -4.0093682958E-01 1.2322769397E+00 4.3830595552E-02 - 1.5582828152E+00 4.3830595552E-02 -1.0146011054E+00 -:PRESIO: 8.9362675994E-01 -:PRES: 6.9170912408E-01 -:PRESIG: 9.2691316414E-01 + -3.4766507520E+00 -3.1575554200E-01 1.2126413707E+00 + -3.1575554200E-01 1.3185109161E+00 4.4104591066E-02 + 1.2126413707E+00 4.4104591066E-02 -2.7163345947E+00 +:CONSTRESS: + 4.0228536266E+00 6.1708500967E-01 -2.3560059152E+00 + 6.1708500967E-01 -6.2468952278E+00 2.6074207246E-01 + -2.3560059152E+00 2.6074207246E-01 2.2240416011E+00 +:TOTSTRESS: + 5.1191620013E-01 -3.0358971070E-01 1.1556692855E+00 + -3.0358971070E-01 5.7346528742E+00 -1.2995569685E-01 + 1.1556692855E+00 -1.2995569685E-01 1.3834809682E+00 +:PRESIO: 9.1852520398E-01 +:PRES: 1.6248248102E+00 +:CONPRES: -1.3290970473E-16 +:TOTPRES: 2.5433500142E+00 +:PRESIG: 9.4815504927E-01 :MIND: -Al - Al: 4.8679586786E+00 -Si - Si: 4.7292754053E+00 -Al - Si: 4.7432974943E+00 -:MDSTEP: 32 -:MDTM: 1.56 +Al - Al: 4.7219757644E+00 +Si - Si: 4.7547257654E+00 +Al - Si: 4.8767584542E+00 + + +:MDSTEP: 22 +:MDTM: 15.36 :TWIST: 0 :TEL: 1120 -:TIO: 1121.60585761912 -:TEN: -3.2410163607E+00 -:KEN: 5.1613756118E-03 -:KENIG: 5.3278715993E-03 -:FEN: -3.2461777363E+00 -:UEN: -3.2454267026E+00 -:TSEN: -7.5103373329E-04 -:NPT_NP_HAMIL: -2.7772649594E-05 +:TIO: 1118.21960596524 +:TEN: -3.2407259163E+00 +:KEN: 5.1457928502E-03 +:KENIG: 5.3117861680E-03 +:FEN: -3.2458717091E+00 +:UEN: -3.2449628592E+00 +:TSEN: -9.0884996332E-04 +:NPT_NP_HAMIL: -5.3891369204E-05 +:SNOSE[0]: 1.0071532493E+00 +:SNOSE[1]: 4.4048358209E-05 :R: - 3.5751639925E-01 4.1863277208E-01 2.4415464765E-01 - 3.9048746702E+00 1.5327862898E+01 4.1153045935E+00 - 8.0046395096E+00 1.5161787928E+01 9.5808294210E-02 - 1.1361265382E+01 1.5331256746E+01 3.6175044405E+00 - 1.5986489870E-01 7.9272910568E+00 1.5336914614E+01 - 3.7268433519E+00 7.9258093287E+00 3.8064625629E+00 - 7.2585877574E+00 7.3983152070E+00 1.6234256918E-01 - 1.1533742038E+01 7.7880356274E+00 4.0468645855E+00 - 5.6434355144E-01 1.5143960325E+01 7.7424317953E+00 - 3.6333976402E+00 3.3671390868E-02 1.1213489928E+01 - 7.6974545607E+00 5.2424168046E-02 7.7973131553E+00 - 1.1592897712E+01 1.5149473262E+01 1.1771964529E+01 - 3.0996842747E-01 7.7025173873E+00 7.8938705096E+00 - 4.2508625570E+00 7.8956246678E+00 1.1483639041E+01 - 7.3004038949E+00 8.0248877369E+00 7.5241908973E+00 - 1.1534512230E+01 7.2379087097E+00 1.1490125081E+01 - 1.0129380980E-01 3.9368537369E+00 3.9430655378E+00 - 3.7098573152E+00 3.8707800252E+00 1.5534207343E-02 - 7.8567545292E+00 3.6181568327E+00 3.3816383305E+00 - 1.1356673865E+01 3.8131619531E+00 1.5190778522E+01 - 3.4477766140E-01 1.1419998294E+01 3.9235008392E+00 - 3.6001489690E+00 1.1569904502E+01 4.9925785719E-01 - 7.8556682458E+00 1.1710599476E+01 3.8412303112E+00 - 1.1005509096E+01 1.1508956268E+01 8.4085749154E-02 - 1.5328092147E-01 3.6990977386E+00 1.1218242461E+01 - 3.8130109937E+00 3.6871284335E+00 7.9950415618E+00 - 7.9494778013E+00 3.7653349173E+00 1.1540401029E+01 - 1.1355152462E+01 3.9742636992E+00 7.8415449778E+00 - 3.0618367465E-01 1.1530682283E+01 1.1505626840E+01 - 3.6683652650E+00 1.1228666227E+01 7.8149568167E+00 - 7.8755471432E+00 1.1765277765E+01 1.1721023496E+01 - 1.1636606609E+01 1.1537306935E+01 7.8487400090E+00 + 3.7668656984E-01 2.8924008364E-01 1.6648249117E-01 + 3.8379941718E+00 1.5202861316E+01 3.9993620714E+00 + 7.8477952315E+00 1.5087956779E+01 1.6900006203E-01 + 1.1302751401E+01 1.5207610055E+01 3.6462357898E+00 + 1.0944797264E-01 7.7885404787E+00 1.5211159654E+01 + 3.7332607927E+00 7.7801813934E+00 3.7821786532E+00 + 7.3156115087E+00 7.4176175058E+00 1.0815613952E-01 + 1.1429817820E+01 7.6868371884E+00 3.9498742593E+00 + 5.3681450781E-01 1.5078670363E+01 7.6633327424E+00 + 3.6517944413E+00 2.3986134773E-02 1.1196119795E+01 + 7.6224018006E+00 3.6459908608E-02 7.7888929979E+00 + 1.1462690690E+01 1.5081500244E+01 1.1591046952E+01 + 2.1168272836E-01 7.6262015875E+00 7.7576786143E+00 + 4.0935686339E+00 7.7661487993E+00 1.1394725469E+01 + 7.3469834999E+00 7.8535822363E+00 7.5060921104E+00 + 1.1433130419E+01 7.3148055036E+00 1.1397031258E+01 + 6.1586106982E-02 3.8755848069E+00 3.8784255270E+00 + 3.7231741828E+00 3.8268904025E+00 1.5223827540E+01 + 7.7285947224E+00 3.6579614147E+00 3.5118287412E+00 + 1.1326350044E+01 3.7781169526E+00 1.5110754891E+01 + 3.0690765987E-01 1.1354040761E+01 3.8649756223E+00 + 3.6462694832E+00 1.1454402593E+01 4.8147208536E-01 + 7.7244208043E+00 1.1550812387E+01 3.8290388291E+00 + 1.1096525606E+01 1.1407815953E+01 4.5847229766E-02 + 1.0020183878E-01 3.7070684478E+00 1.1227324739E+01 + 3.7998082114E+00 3.7029483139E+00 7.8128159752E+00 + 7.7805882081E+00 3.7530371893E+00 1.1439443563E+01 + 1.1310207497E+01 3.9002886639E+00 7.7139984082E+00 + 2.9082555321E-01 1.1423379436E+01 1.1427462743E+01 + 3.7164404313E+00 1.1220606182E+01 7.8636812107E+00 + 7.7239594790E+00 1.1586824077E+01 1.1570126195E+01 + 1.1507097536E+01 1.1431544288E+01 7.7118651369E+00 :V: - -9.2150266390E-05 4.9074125832E-04 2.9934646032E-04 - 1.5544931456E-04 -3.4770618056E-05 3.0648183352E-04 - 3.0728804219E-04 -2.2221710194E-04 -3.1195472805E-04 - -1.4063258310E-04 -4.3608051324E-05 -2.1951102981E-04 - 1.9152214135E-04 2.6378838925E-04 -3.3419230366E-05 - -1.6368523206E-04 3.0865247155E-04 -3.4467932748E-05 - -4.5744145125E-04 -3.2481067152E-04 2.1011641665E-04 - 1.4433190909E-05 1.3607082247E-04 2.4624703026E-04 - 3.6858811212E-05 -2.6857006464E-04 2.4601688717E-05 - -1.6717479271E-04 2.7998798364E-05 -2.8180701872E-04 - 3.5155430239E-05 6.3588161106E-05 -2.3169530575E-04 - 1.3359204806E-04 -2.5662611930E-04 3.0698265197E-04 - 3.7143475968E-04 4.1019280199E-05 2.7005871508E-04 - 4.6837700666E-04 2.3014422244E-04 -3.9520533704E-05 - -4.1699946100E-04 3.9055836622E-04 -1.9437418073E-04 - 5.5327764816E-07 -5.6023119988E-04 -2.2691772523E-05 - 1.7783399081E-04 1.0410950000E-04 1.1459846297E-04 - -1.9607139484E-04 4.2414731919E-05 9.9259036080E-05 - 2.4071694646E-04 -2.9426660994E-04 -6.6740107469E-04 - -3.1325941496E-04 3.1482031811E-05 -2.0679983544E-04 - 1.8259880310E-04 -1.4185628227E-04 1.0188015214E-04 - -3.0870207191E-04 5.9113056033E-05 8.6818382714E-05 - 2.5546239293E-04 2.2578796868E-04 -1.1850033211E-04 - -7.8715066544E-04 4.8353590936E-06 1.6151506105E-04 - 2.1015122065E-04 -1.5263929026E-04 -4.5357867477E-04 - -1.0216932610E-04 -1.9252509171E-04 4.6500253403E-04 - 4.2778434001E-04 -7.9191600825E-05 -7.7551949988E-06 - -2.2172003612E-04 1.4945554976E-04 2.6088088445E-04 - 7.1516584633E-05 3.8489404127E-05 -1.1661493525E-04 - -3.7548332693E-04 -3.4911484362E-04 -4.7334079146E-04 - 3.6741679894E-04 3.0459716438E-04 1.7573169914E-04 - 1.0536177843E-04 1.7078516348E-05 2.9547828488E-04 + -8.3443683075E-05 5.2651253539E-04 3.0917352526E-04 + 1.0545144969E-04 -3.8046465730E-05 3.4300516964E-04 + 3.9633857851E-04 -2.4988962188E-04 -2.8383791788E-04 + -1.8972109677E-04 -3.8467079987E-05 -2.6852122451E-04 + 2.0413319638E-04 3.0116111894E-04 -3.2687099584E-05 + -1.4930975920E-04 3.1159131253E-04 -3.9199290286E-05 + -5.2002379092E-04 -3.5408873800E-04 2.1364911915E-04 + 1.2989202659E-05 1.3315895145E-04 2.5693464367E-04 + 1.5462682231E-04 -2.7291052337E-04 6.9480380621E-05 + -2.4063930539E-04 4.5674709045E-05 -3.7192091439E-04 + 2.5540544911E-05 6.4316151877E-05 -2.4727776843E-04 + 1.0003901262E-04 -2.6473370186E-04 3.2406596471E-04 + 3.9820020011E-04 3.2321515208E-05 2.7264860067E-04 + 5.0790569835E-04 2.6218321681E-04 -5.1636682062E-05 + -4.7643369253E-04 4.2897732198E-04 -1.9278827897E-04 + 9.0042972405E-06 -5.7041733300E-04 -3.5486239027E-05 + 1.3625590064E-04 1.1513278810E-04 1.3086200698E-04 + -1.7206624671E-04 3.9371594001E-05 4.9153159450E-05 + 2.3774381139E-04 -2.8287682512E-04 -6.1759387044E-04 + -2.3952925127E-04 -1.8498066880E-05 -2.1929148615E-04 + 9.5589483568E-05 -1.3243400643E-04 9.5215022851E-05 + -3.1665755784E-04 5.7257945157E-05 2.0899234609E-05 + 2.4655246650E-04 2.3873074738E-04 -4.8689442724E-05 + -7.1494240728E-04 -1.7530412204E-06 1.3652918987E-04 + 2.0384161326E-04 -1.7370080673E-04 -4.0719752200E-04 + -5.6252303106E-05 -1.9602205276E-04 4.3530104984E-04 + 3.7131944766E-04 -8.8775912293E-05 1.1799144106E-05 + -2.1548789902E-04 1.6894657791E-04 2.1395200350E-04 + 2.8283451987E-05 1.5815370974E-05 -5.9755416929E-05 + -2.6911056132E-04 -3.7724700272E-04 -4.7032793430E-04 + 2.9564879711E-04 3.0939573302E-04 2.2088874293E-04 + 1.2415909635E-04 2.1782030107E-05 2.5308964944E-04 :F: - -7.8651608207E-04 -6.1578137929E-03 -1.4422553543E-03 - 1.0852205835E-02 2.4745362980E-05 -6.8741976254E-03 - -2.1227274587E-02 7.2144489020E-03 -7.0064920146E-03 - 1.0913754610E-02 -1.2441254701E-03 1.0746987284E-02 - -2.2197771957E-03 -6.6879250149E-03 -4.3162808159E-04 - -3.4668940941E-03 4.9651262782E-04 -9.5654528867E-05 - 1.1438192771E-02 5.2735911557E-03 -1.4026556947E-03 - 1.2220924937E-03 1.7230812678E-03 2.1625026494E-04 - -2.5497930580E-02 -9.0303245022E-04 -1.0426880424E-02 - 1.6146210090E-02 -5.5283399403E-03 2.0553137792E-02 - 1.8866324025E-03 1.2520432587E-03 3.9126348215E-03 - 9.1926661974E-03 2.7576032460E-04 -3.8323893373E-03 - -6.7124567888E-03 1.4722586471E-03 2.0338108898E-04 - -5.5642563884E-03 -5.5069360439E-03 4.0050219139E-03 - 1.2828150565E-02 -7.5087812835E-03 -2.6348565793E-03 - -2.9549193585E-04 1.4260456867E-03 2.9244322051E-03 - 1.1405690392E-02 -1.1790268841E-03 -3.9201537826E-03 - -7.0061673499E-03 1.3564741246E-03 1.0549591420E-02 - 7.6492917263E-04 -4.7668820999E-03 -1.2252594169E-02 - -1.8261771373E-02 1.1605867429E-02 2.3123016903E-03 - 1.8511919964E-02 -2.9559981026E-03 2.3633624839E-03 - 1.4973704697E-03 1.1615806623E-03 1.4798243645E-02 - 6.4638685251E-04 -2.4858753425E-03 -1.4087903555E-02 - -1.4414269740E-02 -1.0870934315E-03 4.9040968514E-03 - 2.8727485654E-04 4.1040322237E-03 -1.1140648444E-02 - -9.7230723424E-03 5.1478101542E-04 4.7574596995E-03 - 1.3440786198E-02 6.2552019214E-04 -3.8042874579E-03 - -2.5045564322E-03 -4.6571951654E-03 1.1405226873E-02 - 9.1882460761E-03 6.3624273293E-03 -1.1808470942E-02 - -2.5267386754E-02 7.3018878368E-03 -2.5632651422E-03 - 1.4681431448E-02 3.4196326191E-04 -8.8164809098E-03 - -1.9561187490E-03 -1.8639962868E-03 8.8886860081E-03 -:LATVEC_SCALE: 1.5361480701E+01 1.5361480701E+01 1.5361480701E+01 + -3.0176879312E-03 -4.4933953999E-03 -1.0926468252E-03 + 1.0386215937E-02 7.5447957506E-04 -5.0648653249E-03 + -1.2919628627E-02 2.9484392390E-03 -6.2586810372E-03 + 7.7275612426E-03 -1.1133263835E-03 7.7617469683E-03 + -1.3459836926E-03 -6.0942478648E-03 -4.1783686996E-04 + -3.1081303239E-03 1.0420599390E-03 1.4465351790E-03 + 9.7175496155E-03 3.9193829781E-03 9.6785196948E-04 + -2.0842144146E-04 5.1276036300E-04 -1.6858277449E-03 + -2.0653946978E-02 5.2233129637E-04 -7.2690869776E-03 + 1.2155226227E-02 -1.8691102488E-03 1.3527837175E-02 + 1.5660928947E-03 -4.3588428347E-04 1.1341215098E-03 + 5.5881777808E-03 8.0020651727E-04 -6.7100647081E-04 + -1.8635956997E-03 2.3929950771E-03 5.8547632091E-04 + -6.3533004145E-03 -5.1907290179E-03 7.1519006851E-04 + 7.5544538100E-03 -5.1021673602E-03 -7.0855267580E-05 + -2.2304712426E-03 -1.4055897678E-03 2.3249107066E-03 + 7.7894549247E-03 -2.5998318555E-03 -1.7163799179E-03 + -4.5049267439E-03 3.5585689094E-04 1.1173631965E-02 + 2.4873795760E-03 -2.6212848509E-03 -1.4197822107E-02 + -1.5845561038E-02 9.8542021878E-03 1.0748191109E-03 + 2.0557751302E-02 -2.6089429835E-03 9.8229113986E-04 + -8.7623687129E-04 -3.1156511373E-04 1.4970592921E-02 + 4.9687957080E-03 -1.3150653472E-03 -1.6877428620E-02 + -2.1875902738E-02 3.8937878476E-03 6.7418006786E-03 + 3.2215420822E-03 3.4461163598E-03 -1.1779355252E-02 + -1.0615784237E-02 -9.0286445532E-04 1.0515980543E-02 + 1.3570730135E-02 2.4033916223E-03 -4.3132517292E-03 + -1.7598322082E-03 -2.1884988198E-03 9.7418360934E-03 + 1.0336729550E-02 3.7615869485E-03 -1.3795526755E-02 + -2.3958326412E-02 1.6626801066E-03 -1.2255942646E-03 + 1.8489023454E-02 4.5586211169E-04 -8.9934368737E-03 + -4.9789476392E-03 -4.7363530782E-04 1.1764979687E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5308352609E+03 +:LATVEC_SCALE: + 1.5227402182E+01 1.5227402182E+01 1.5227402182E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0715276313E+00 -2.5046466129E-02 4.0776758537E-02 - -2.5046466129E-02 -6.9696845681E-01 -1.6679743733E-01 - 4.0776758537E-02 -1.6679743733E-01 -8.9814090136E-01 + 1.0579177614E+00 2.4879716394E-04 6.5145680033E-03 + 2.4879716394E-04 7.9563117116E-01 1.7381894010E-01 + 6.5145680033E-03 1.7381894010E-01 8.9063034114E-01 :STRESS: - -2.1163149961E+00 -4.1339720112E-01 1.5803770515E+00 - -4.1339720112E-01 1.2748805322E+00 4.4542827504E-02 - 1.5803770515E+00 4.4542827504E-02 -7.9709831992E-01 -:PRESIO: 8.8887899647E-01 -:PRES: 5.4617759462E-01 -:PRESIG: 9.2250959536E-01 + -3.2275270915E+00 -3.2141432555E-01 1.2422816197E+00 + -3.2141432555E-01 1.3548858333E+00 4.2313971271E-02 + 1.2422816197E+00 4.2313971271E-02 -2.4131197518E+00 +:CONSTRESS: + 3.9201652424E+00 6.3289127778E-01 -2.4275886494E+00 + 6.3289127778E-01 -5.9371275451E+00 2.6220122807E-01 + -2.4275886494E+00 2.6220122807E-01 2.0169623027E+00 +:TOTSTRESS: + 3.6527961050E-01 -3.1122815507E-01 1.1918215976E+00 + -3.1122815507E-01 5.3778728830E+00 -1.3069625924E-01 + 1.1918215976E+00 -1.3069625924E-01 1.2867877902E+00 +:PRESIO: 9.1472642458E-01 +:PRES: 1.4285870033E+00 +:CONPRES: 1.0287211146E-13 +:TOTPRES: 2.3433134279E+00 +:PRESIG: 9.4423372860E-01 :MIND: -Al - Al: 4.8680592310E+00 -Si - Si: 4.7270872873E+00 -Al - Si: 4.7274236987E+00 -:MDSTEP: 33 -:MDTM: 1.46 +Al - Al: 4.7131216661E+00 +Si - Si: 4.7549454328E+00 +Al - Si: 4.8726654462E+00 + + +:MDSTEP: 23 +:MDTM: 15.32 :TWIST: 0 :TEL: 1120 -:TIO: 1119.77856121439 -:TEN: -3.2410511755E+00 -:KEN: 5.1529668085E-03 -:KENIG: 5.3191915442E-03 -:FEN: -3.2462041423E+00 -:UEN: -3.2454618728E+00 -:TSEN: -7.4226945802E-04 -:NPT_NP_HAMIL: -2.7434210865E-05 +:TIO: 1118.40635695649 +:TEN: -3.2407652396E+00 +:KEN: 5.1466522359E-03 +:KENIG: 5.3126732758E-03 +:FEN: -3.2459118918E+00 +:UEN: -3.2450232342E+00 +:TSEN: -8.8865760275E-04 +:NPT_NP_HAMIL: -7.0216114672E-05 +:SNOSE[0]: 1.0078240072E+00 +:SNOSE[1]: 3.4244932892E-05 :R: - 3.5566432581E-01 4.3123062479E-01 2.5185428518E-01 - 3.9136768670E+00 1.5345902897E+01 4.1278867541E+00 - 8.0218583363E+00 1.5175068812E+01 8.8109924023E-02 - 1.1371927304E+01 1.5349066121E+01 3.6166609698E+00 - 1.6477943399E-01 7.9435184295E+00 1.5354993554E+01 - 3.7273402418E+00 7.9432361935E+00 3.8103012353E+00 - 7.2563478863E+00 7.3994566603E+00 1.6773106013E-01 - 1.1548337445E+01 7.8010320561E+00 4.0579585738E+00 - 5.6563406968E-01 1.5155969359E+01 7.7524584231E+00 - 3.6339379103E+00 3.4337530946E-02 1.1220592342E+01 - 7.7078410631E+00 5.4079913492E-02 7.8012366369E+00 - 1.1610617929E+01 1.5161799746E+01 1.1794038721E+01 - 3.1946942429E-01 7.7130502375E+00 7.9102981312E+00 - 4.2676393479E+00 7.9109941831E+00 1.1496870684E+01 - 7.2992349437E+00 8.0443660452E+00 7.5286204391E+00 - 1.1548745737E+01 7.2329715250E+00 1.1503768168E+01 - 1.0596163500E-01 3.9442736240E+00 3.9507200537E+00 - 3.7094900781E+00 3.8766203268E+00 1.8139236321E-02 - 7.8724160537E+00 3.6152705209E+00 3.3691257507E+00 - 1.1362697550E+01 3.8187833719E+00 1.5204414744E+01 - 3.4994908942E-01 1.1430530470E+01 3.9308915498E+00 - 3.5969579964E+00 1.1585650160E+01 5.0220215046E-01 - 7.8716923398E+00 1.1730604369E+01 3.8428619580E+00 - 1.0999404842E+01 1.1523254996E+01 8.8249991970E-02 - 1.5868007537E-01 3.6999266727E+00 1.1220704386E+01 - 3.8150648545E+00 3.6869113144E+00 8.0164784214E+00 - 7.9700405958E+00 3.7680235080E+00 1.1554393972E+01 - 1.1363631395E+01 3.9828114553E+00 7.8578150550E+00 - 3.0844342393E-01 1.1545931037E+01 1.1516783718E+01 - 3.6632825560E+00 1.1233950581E+01 7.8128354061E+00 - 7.8945380033E+00 1.1787336600E+01 1.1739725059E+01 - 1.1653542949E+01 1.1551934632E+01 7.8658459323E+00 + 3.7507262532E-01 3.0265020148E-01 1.7436247269E-01 + 3.8455341870E+00 1.5221160113E+01 4.0129075297E+00 + 7.8674857305E+00 1.5100864274E+01 1.6212762894E-01 + 1.1312392632E+01 1.5225892725E+01 3.6442317361E+00 + 1.1464625702E-01 7.8058356632E+00 1.5229594676E+01 + 3.7342585897E+00 7.7977696381E+00 3.7860006863E+00 + 7.3120188736E+00 7.4182374823E+00 1.1360353611E-01 + 1.1444603046E+01 7.6998738859E+00 3.9612412929E+00 + 5.4120358726E-01 1.5090979355E+01 7.6747099681E+00 + 3.6505171789E+00 2.5138795858E-02 1.1201138753E+01 + 7.6326916077E+00 3.8100156548E-02 7.7926172703E+00 + 1.1479715074E+01 1.5094017570E+01 1.1613756709E+01 + 2.2182543227E-01 7.6366697376E+00 7.7742686564E+00 + 4.1113193827E+00 7.7824535632E+00 1.1407867540E+01 + 7.3444992752E+00 7.8741393541E+00 7.5108038264E+00 + 1.1447808240E+01 7.3098910420E+00 1.1410587307E+01 + 6.5093847639E-02 3.8833320978E+00 3.8865722507E+00 + 3.7235865819E+00 3.8327128548E+00 1.5244380340E+01 + 7.7442926407E+00 3.6555514195E+00 3.5008538534E+00 + 1.1334640819E+01 3.7824980283E+00 1.5124438930E+01 + 3.0979297986E-01 1.1365105146E+01 3.8722365157E+00 + 3.6430164818E+00 1.1470317463E+01 4.8269029989E-01 + 7.7403470665E+00 1.1571348822E+01 3.8325739726E+00 + 1.1092685741E+01 1.1422232041E+01 4.9335537331E-02 + 1.0540898638E-01 3.7074677059E+00 1.1231351798E+01 + 3.8031562560E+00 3.7027620097E+00 7.8335737031E+00 + 7.7997349943E+00 3.7555968585E+00 1.1454186785E+01 + 1.1319159462E+01 3.9094057767E+00 7.7291307870E+00 + 2.9195797499E-01 1.1438250611E+01 1.1440357217E+01 + 3.7143178919E+00 1.1225449198E+01 7.8619477750E+00 + 7.7411854385E+00 1.1609171201E+01 1.1590197907E+01 + 1.1524712034E+01 1.1446548462E+01 7.7279786920E+00 :V: - -9.2331282544E-05 4.8649949284E-04 2.9792328795E-04 - 1.6054737540E-04 -3.4677148851E-05 3.0230896130E-04 - 2.9589156178E-04 -2.1806937706E-04 -3.1475315217E-04 - -1.3481365711E-04 -4.4132420621E-05 -2.1359221880E-04 - 1.8995900020E-04 2.5980871932E-04 -3.3558533645E-05 - -1.6504819369E-04 3.0818310363E-04 -3.4435747856E-05 - -4.5062046231E-04 -3.2140043429E-04 2.0892108268E-04 - 1.5014454348E-05 1.3662073125E-04 2.4578205893E-04 - 2.3943680486E-05 -2.6839863212E-04 1.9298094990E-05 - -1.5866131871E-04 2.5151982543E-05 -2.7080910228E-04 - 3.6022771312E-05 6.4069958805E-05 -2.2918679873E-04 - 1.3790604332E-04 -2.5588940937E-04 3.0433909419E-04 - 3.6719192107E-04 4.1664466435E-05 2.6953178531E-04 - 4.6448599940E-04 2.2683715927E-04 -3.7413326457E-05 - -4.0957335024E-04 3.8587029842E-04 -1.9524699595E-04 - 4.0331212748E-07 -5.5820829889E-04 -2.1167474906E-05 - 1.8293290221E-04 1.0329699789E-04 1.1243651528E-04 - -1.9900117092E-04 4.2971594033E-05 1.0412721311E-04 - 2.4052580601E-04 -2.9588515724E-04 -6.7176862771E-04 - -3.2135686418E-04 3.7018717735E-05 -2.0520025363E-04 - 1.9112161987E-04 -1.4295461436E-04 1.0278516406E-04 - -3.0725897017E-04 5.9536802015E-05 9.3769260219E-05 - 2.5517959333E-04 2.2406024084E-04 -1.2503402383E-04 - -7.9228410163E-04 4.2986132778E-06 1.6350925803E-04 - 2.0980041260E-04 -1.5029982096E-04 -4.5790696076E-04 - -1.0663119928E-04 -1.9182765650E-04 4.6621869695E-04 - 4.3328456921E-04 -7.8704713576E-05 -9.5760404076E-06 - -2.2241406082E-04 1.4685611108E-04 2.6578606519E-04 - 7.5791357194E-05 4.1475189245E-05 -1.2205118843E-04 - -3.8682216189E-04 -3.4477179014E-04 -4.7347689618E-04 - 3.7365739269E-04 3.0405272421E-04 1.7106052001E-04 - 1.0417072789E-04 1.6137703750E-05 2.9908640561E-04 + -8.4726964170E-05 5.2318485155E-04 3.0801204413E-04 + 1.1051090420E-04 -3.7620706268E-05 3.3974580669E-04 + 3.8888093455E-04 -2.4786066010E-04 -2.8646163844E-04 + -1.8538850077E-04 -3.8967872029E-05 -2.6402493561E-04 + 2.0303290307E-04 2.9749426212E-04 -3.2830693681E-05 + -1.5061346174E-04 3.1154027334E-04 -3.8424005981E-05 + -5.1407902638E-04 -3.5139649842E-04 2.1367232412E-04 + 1.2893054105E-05 1.3319937970E-04 2.5563148772E-04 + 1.4380510811E-04 -2.7215490850E-04 6.5595645460E-05 + -2.3395193998E-04 4.4561727543E-05 -3.6422359970E-04 + 2.6271998777E-05 6.4016303150E-05 -2.4615234222E-04 + 1.0273618044E-04 -2.6384864928E-04 3.2303415616E-04 + 3.9639118290E-04 3.3472518590E-05 2.7240963354E-04 + 5.0373647986E-04 2.5904678386E-04 -5.1105385667E-05 + -4.7158940432E-04 4.2552681420E-04 -1.9251983858E-04 + 7.9081429551E-06 -5.6999015822E-04 -3.4231785089E-05 + 1.3987696977E-04 1.1368344164E-04 1.2973203782E-04 + -1.7396825998E-04 3.9486291814E-05 5.4462125000E-05 + 2.3842052287E-04 -2.8367021503E-04 -6.2325841759E-04 + -2.4682243227E-04 -1.3623074566E-05 -2.1833265802E-04 + 1.0537689437E-04 -1.3347537699E-04 9.5569986918E-05 + -3.1640983044E-04 5.7026742211E-05 2.8136431466E-05 + 2.4837137606E-04 2.3761515504E-04 -5.6720533208E-05 + -7.2404769593E-04 6.5684540841E-08 1.3945335574E-04 + 2.0495313009E-04 -1.7167759777E-04 -4.1214536532E-04 + -6.1295816369E-05 -1.9608029633E-04 4.3943102844E-04 + 3.7720890884E-04 -8.7468714908E-05 9.7031775969E-06 + -2.1593729768E-04 1.6751381492E-04 2.1835877449E-04 + 3.3200954079E-05 1.7673746646E-05 -6.6285584001E-05 + -2.8027823319E-04 -3.7560941363E-04 -4.7008861819E-04 + 3.0398869171E-04 3.0904672501E-04 2.1615982052E-04 + 1.2159561649E-04 2.1477540589E-05 2.5823228798E-04 :F: - -6.0426106106E-04 -6.1878180454E-03 -1.4776210921E-03 - 1.0788052749E-02 -4.8295009346E-05 -6.9713512143E-03 - -2.1982783245E-02 7.7766085564E-03 -6.9867607543E-03 - 1.1108077352E-02 -1.2174564247E-03 1.0972611578E-02 - -2.2293324360E-03 -6.6544305969E-03 -4.7549676008E-04 - -3.4056245298E-03 3.6659749470E-04 -3.0690165303E-04 - 1.1446373846E-02 5.3047751211E-03 -1.6777138949E-03 - 1.3919277601E-03 1.8165698921E-03 5.1631404251E-04 - -2.5721610533E-02 -1.0684068422E-03 -1.0599714789E-02 - 1.6391935626E-02 -5.8873730649E-03 2.1099829563E-02 - 1.9192403800E-03 1.4415087409E-03 4.1354370378E-03 - 9.5628835393E-03 2.2262322794E-04 -4.1038413534E-03 - -7.2203731194E-03 1.2585016990E-03 1.7158818156E-04 - -5.3733614099E-03 -5.3995102189E-03 4.3086576691E-03 - 1.3190916659E-02 -7.6699276349E-03 -2.9189315192E-03 - -1.0743838608E-05 1.7623780313E-03 2.9914834762E-03 - 1.1658810272E-02 -1.0325911965E-03 -4.1161383275E-03 - -7.2537294471E-03 1.4648526979E-03 1.0415472357E-02 - 7.8364764659E-04 -4.9372436840E-03 -1.2068964971E-02 - -1.8424535803E-02 1.1630185209E-02 2.4913853653E-03 - 1.8116364235E-02 -2.9341351242E-03 2.3851895506E-03 - 1.6379256042E-03 1.2993994424E-03 1.4745134277E-02 - 2.8554405814E-04 -2.5915245401E-03 -1.3750105304E-02 - -1.3502747303E-02 -1.6796846320E-03 4.8094105576E-03 - -4.7354388363E-05 4.1194303021E-03 -1.0944745330E-02 - -9.5646823585E-03 7.2882167713E-04 4.1338762171E-03 - 1.3271819485E-02 3.5231812194E-04 -3.7252704257E-03 - -2.5875510069E-03 -4.8632318925E-03 1.1260919734E-02 - 9.1638266128E-03 6.5598608095E-03 -1.1608860798E-02 - -2.5231112816E-02 7.8161224490E-03 -2.4460433282E-03 - 1.4105771372E-02 2.7390846427E-04 -8.8846222956E-03 - -1.6633139017E-03 -2.0228330303E-03 8.6257742035E-03 -:LATVEC_SCALE: 1.5380423321E+01 1.5380423321E+01 1.5380423321E+01 + -2.7154401191E-03 -4.6850361678E-03 -1.1509446700E-03 + 1.0504640355E-02 6.4442727986E-04 -5.2472221803E-03 + -1.3648858375E-02 3.1923187013E-03 -6.3291361369E-03 + 8.0181314089E-03 -1.1690179581E-03 8.0304934130E-03 + -1.4588091113E-03 -6.1558564683E-03 -4.0241743184E-04 + -3.2099121798E-03 1.1406448143E-03 1.3310025868E-03 + 9.8991601278E-03 4.0566811327E-03 7.6006230801E-04 + -7.3933981942E-05 6.6697668360E-04 -1.5202801763E-03 + -2.1119025402E-02 3.8795891725E-04 -7.6192572326E-03 + 1.2547900952E-02 -2.1989256598E-03 1.4179037059E-02 + 1.5329976554E-03 -2.6216813858E-04 1.4399556461E-03 + 5.8838923506E-03 6.8646938162E-04 -9.4362858313E-04 + -2.2685305864E-03 2.4233627712E-03 5.5324041166E-04 + -6.3083063732E-03 -5.2522364291E-03 9.9822939015E-04 + 8.0273015023E-03 -5.3104873819E-03 -3.3920180303E-04 + -2.0519910985E-03 -1.2657163612E-03 2.3829656134E-03 + 8.2576781379E-03 -2.4713619923E-03 -1.9095354655E-03 + -4.7248784865E-03 4.3172496036E-04 1.1154062019E-02 + 2.2034764646E-03 -2.9107671659E-03 -1.4128835269E-02 + -1.6197345782E-02 1.0140984253E-02 1.1394244610E-03 + 2.0644258370E-02 -2.7490548354E-03 1.2428588788E-03 + -6.2375611557E-04 -1.8758899258E-04 1.5099027175E-02 + 4.5118420770E-03 -1.3919924121E-03 -1.6694212955E-02 + -2.1443560266E-02 3.6072701153E-03 6.4287457872E-03 + 2.9956658341E-03 3.5292952172E-03 -1.1909206667E-02 + -1.0671591329E-02 -8.9982186724E-04 1.0017818047E-02 + 1.3722560276E-02 2.2904730899E-03 -4.2530586694E-03 + -1.8141196326E-03 -2.3850380304E-03 1.0170889877E-02 + 1.0207288633E-02 4.0427478868E-03 -1.3662616363E-02 + -2.4329203526E-02 2.0970734395E-03 -1.5331556685E-03 + 1.8326467638E-02 5.6743367482E-04 -8.7859064686E-03 + -4.6239994169E-03 -6.1077245801E-04 1.1500803066E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5442566767E+03 +:LATVEC_SCALE: + 1.5246671927E+01 1.5246671927E+01 1.5246671927E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0719244685E+00 -2.7511261742E-02 4.4021271925E-02 - -2.7511261742E-02 -6.8540155908E-01 -1.6540507576E-01 - 4.4021271925E-02 -1.6540507576E-01 -8.9705866134E-01 + 1.0583536580E+00 2.7900197446E-03 9.3479562059E-04 + 2.7900197446E-03 7.8532888850E-01 1.7286792217E-01 + 9.3479562059E-04 1.7286792217E-01 8.9056161296E-01 :STRESS: - -1.9448701209E+00 -4.2667027552E-01 1.5999581629E+00 - -4.2667027552E-01 1.3200245589E+00 4.5606494038E-02 - 1.5999581629E+00 4.5606494038E-02 -5.9177087843E-01 -:PRESIO: 8.8479489632E-01 -:PRES: 4.0553881347E-01 -:PRESIG: 9.1760790013E-01 + -2.9793397170E+00 -3.2759903649E-01 1.2709987231E+00 + -3.2759903649E-01 1.4001563654E+00 4.0719016072E-02 + 1.2709987231E+00 4.0719016072E-02 -2.1076388020E+00 +:CONSTRESS: + 3.8266849818E+00 6.4977877917E-01 -2.4972413813E+00 + 6.4977877917E-01 -5.6381831694E+00 2.6359753825E-01 + -2.4972413813E+00 2.6359753825E-01 1.8114981876E+00 +:TOTSTRESS: + 2.1100839318E-01 -3.1938972294E-01 1.2271774537E+00 + -3.1938972294E-01 5.0233556925E+00 -1.3144863215E-01 + 1.2271774537E+00 -1.3144863215E-01 1.1867022274E+00 +:PRESIO: 9.1141471983E-01 +:PRES: 1.2289407179E+00 +:CONPRES: -1.1297324902E-14 +:TOTPRES: 2.1403554377E+00 +:PRESIG: 9.4081519466E-01 :MIND: -Al - Al: 4.8686661041E+00 -Si - Si: 4.7247264426E+00 -Al - Si: 4.7118496756E+00 -:MDSTEP: 34 -:MDTM: 2.14 +Al - Al: 4.7049156180E+00 +Si - Si: 4.7550470129E+00 +Al - Si: 4.8687878071E+00 + + +:MDSTEP: 24 +:MDTM: 13.69 :TWIST: 0 :TEL: 1120 -:TIO: 1118.78429532201 -:TEN: -3.2410800935E+00 -:KEN: 5.1483914225E-03 -:KENIG: 5.3144685652E-03 -:FEN: -3.2462284849E+00 -:UEN: -3.2454933492E+00 -:TSEN: -7.3513565625E-04 -:NPT_NP_HAMIL: -2.6806707876E-05 +:TIO: 1119.05622816023 +:TEN: -3.2408006262E+00 +:KEN: 5.1496427957E-03 +:KENIG: 5.3157603052E-03 +:FEN: -3.2459502690E+00 +:UEN: -3.2450808781E+00 +:TSEN: -8.6939090128E-04 +:NPT_NP_HAMIL: -8.6439603691E-05 +:SNOSE[0]: 1.0083200258E+00 +:SNOSE[1]: 3.1718221979E-05 :R: - 3.5380844702E-01 4.4374464478E-01 2.5953140981E-01 - 3.9226334598E+00 1.5364031195E+01 4.1403999450E+00 - 8.0388430720E+00 1.5188538201E+01 8.0330531368E-02 - 1.1382795963E+01 1.5366949372E+01 3.6159793905E+00 - 1.6966354972E-01 7.9597035232E+00 1.5373155486E+01 - 3.7278190435E+00 7.9607076458E+00 3.8141586216E+00 - 7.2543011318E+00 7.4007129041E+00 1.7309569392E-01 - 1.1563016394E+01 7.8140935409E+00 4.0690778247E+00 - 5.6660589137E-01 1.5168057157E+01 7.7623967924E+00 - 3.6347068976E+00 3.4929815379E-02 1.1228028022E+01 - 7.7182952232E+00 5.5752807133E-02 7.8052609038E+00 - 1.1628521914E+01 1.5174220934E+01 1.1816123841E+01 - 3.2887523843E-01 7.7236424124E+00 7.9267684257E+00 - 4.2843649577E+00 7.9263375261E+00 1.1510222997E+01 - 7.2982804051E+00 8.0637876377E+00 7.5330603961E+00 - 1.1563045525E+01 7.2281082601E+00 1.1517515202E+01 - 1.1076670160E-01 3.9517018929E+00 3.9583457914E+00 - 3.7090607388E+00 3.8824997234E+00 2.0867523724E-02 - 7.8881278336E+00 3.6123511683E+00 3.3565000024E+00 - 1.1368571262E+01 3.8245657327E+00 1.5218172116E+01 - 3.5533655634E-01 1.1441095790E+01 3.9383316168E+00 - 3.5938130448E+00 1.1601476960E+01 5.0532466970E-01 - 7.8877604335E+00 1.1750641481E+01 3.8443528948E+00 - 1.0993216311E+01 1.1537599751E+01 9.2469481772E-02 - 1.6407570586E-01 3.7008291257E+00 1.1223107859E+01 - 3.8170277666E+00 3.6867276889E+00 8.0380024355E+00 - 7.9908006174E+00 3.7707394523E+00 1.1568408813E+01 - 1.1372148715E+01 3.9913210119E+00 7.8742606536E+00 - 3.1081359337E-01 1.1561324207E+01 1.1527869681E+01 - 3.6579250609E+00 1.1239399763E+01 7.8107382864E+00 - 7.9137367697E+00 1.1809460914E+01 1.1758384301E+01 - 1.1670524420E+01 1.1566604182E+01 7.8830951653E+00 + 3.7343691385E-01 3.1600342016E-01 1.8222897627E-01 + 3.8533179526E+00 1.5239917457E+01 4.0265012377E+00 + 7.8872325129E+00 1.5114261550E+01 1.5518462893E-01 + 1.1322471247E+01 1.5244611384E+01 3.6424396162E+00 + 1.1982687849E-01 7.8232804182E+00 1.5248475314E+01 + 3.7353286299E+00 7.8155984202E+00 3.7899518373E+00 + 7.3087734266E+00 7.4191323764E+00 1.1906088741E-01 + 1.1459725487E+01 7.7131447344E+00 3.9727028844E+00 + 5.4534215603E-01 1.5103743042E+01 7.6862177309E+00 + 3.6495082104E+00 2.6264046017E-02 1.1206671427E+01 + 7.6432258910E+00 3.9737370697E-02 7.7965933094E+00 + 1.1497151111E+01 1.5106993307E+01 1.1636793544E+01 + 2.3194085266E-01 7.6473935360E+00 7.7910917187E+00 + 4.1291057547E+00 7.7989190515E+00 1.1421360048E+01 + 7.3423391700E+00 7.8948568986E+00 7.5157359583E+00 + 1.1462798663E+01 7.3051846172E+00 1.1424510988E+01 + 6.8700971588E-02 3.8911628891E+00 3.8948091120E+00 + 3.7240545769E+00 3.8386532625E+00 1.5265517268E+01 + 7.7602427452E+00 3.6532183415E+00 3.4898209584E+00 + 1.1343075119E+01 3.7871131437E+00 1.5138586769E+01 + 3.1293444974E-01 1.1376474244E+01 3.8796255266E+00 + 3.6398679972E+00 1.1486568373E+01 4.8410410087E-01 + 7.7565530409E+00 1.1592207318E+01 3.8360222895E+00 + 1.1088925648E+01 1.1437029195E+01 5.2900758677E-02 + 1.1065249508E-01 3.7080213832E+00 1.1235573196E+01 + 3.8064891437E+00 3.7026770193E+00 7.8546775435E+00 + 7.8192723273E+00 3.7582963092E+00 1.1469217294E+01 + 1.1328427161E+01 3.9186074628E+00 7.7446110583E+00 + 2.9322140814E-01 1.1453508326E+01 1.1453426376E+01 + 3.7120162098E+00 1.1230654431E+01 7.8604347329E+00 + 7.7588566197E+00 1.1631864108E+01 1.1610503553E+01 + 1.1542609910E+01 1.1461883368E+01 7.7444555643E+00 :V: - -9.2486245587E-05 4.8259727071E-04 2.9669759133E-04 - 1.6571966505E-04 -3.4645397459E-05 2.9831003530E-04 - 2.8434463228E-04 -2.1380120153E-04 -3.1776212983E-04 - -1.2900267303E-04 -4.4674063710E-05 -2.0772206842E-04 - 1.8852937459E-04 2.5603808268E-04 -3.3743690502E-05 - -1.6649609275E-04 3.0786939749E-04 -3.4534597351E-05 - -4.4412852566E-04 -3.1820977470E-04 2.0773854239E-04 - 1.5691025061E-05 1.3731449163E-04 2.4564463048E-04 - 1.0953924144E-05 -2.6850261895E-04 1.3929848906E-05 - -1.5015131000E-04 2.2146974347E-05 -2.5974730222E-04 - 3.6930880620E-05 6.4692177739E-05 -2.2673400765E-04 - 1.4249805821E-04 -2.5536357768E-04 3.0178070055E-04 - 3.6296270339E-04 4.2230766511E-05 2.6918238441E-04 - 4.6102945577E-04 2.2375169598E-04 -3.5183389497E-05 - -4.0226938963E-04 3.8138452590E-04 -1.9640101363E-04 - 3.9725041437E-07 -5.5641837864E-04 -1.9627013369E-05 - 1.8827678628E-04 1.0263048987E-04 1.1026363994E-04 - -2.0218822543E-04 4.3610701091E-05 1.0899708140E-04 - 2.4051597809E-04 -2.9779502036E-04 -6.7652053180E-04 - -3.2974968817E-04 4.2584678918E-05 -2.0366332590E-04 - 1.9957594648E-04 -1.4414279138E-04 1.0377275083E-04 - -3.0596986723E-04 6.0069091405E-05 1.0075024320E-04 - 2.5490512685E-04 2.2244437917E-04 -1.3148313510E-04 - -7.9753470514E-04 3.4791569417E-06 1.6557131921E-04 - 2.0943828678E-04 -1.4806413329E-04 -4.6246083712E-04 - -1.1108547025E-04 -1.9116494722E-04 4.6746454422E-04 - 4.3900392147E-04 -7.8407033337E-05 -1.1362565001E-05 - -2.2330611098E-04 1.4426619573E-04 2.7080351699E-04 - 8.0101587991E-05 4.4581300417E-05 -1.2746934829E-04 - -3.9840165112E-04 -3.4043348348E-04 -4.7389456035E-04 - 3.7987655782E-04 3.0369360796E-04 1.6648622084E-04 - 1.0319771060E-04 1.5133115601E-05 3.0277532849E-04 + -8.5870291601E-05 5.1984695115E-04 3.0686975209E-04 + 1.1563181470E-04 -3.7256490262E-05 3.3645333466E-04 + 3.8112688376E-04 -2.4574191790E-04 -2.8915634537E-04 + -1.8094575018E-04 -3.9499042658E-05 -2.5944027108E-04 + 2.0191087002E-04 2.9385053392E-04 -3.2971553258E-05 + -1.5198515744E-04 3.1158105928E-04 -3.7718422448E-05 + -5.0813570624E-04 -3.4869502866E-04 2.1362013634E-04 + 1.2867796996E-05 1.3333542417E-04 2.5445610062E-04 + 1.3279526651E-04 -2.7151063257E-04 6.1555222954E-05 + -2.2711622139E-04 4.3290163229E-05 -3.5626720882E-04 + 2.6990074286E-05 6.3816819540E-05 -2.4491188525E-04 + 1.0559402311E-04 -2.6306065248E-04 3.2191316297E-04 + 3.9443746225E-04 3.4637501776E-05 2.7219400587E-04 + 4.9967765291E-04 2.5592707427E-04 -5.0437469600E-05 + -4.6658668193E-04 4.2204013565E-04 -1.9241567764E-04 + 6.9079700318E-06 -5.6957373547E-04 -3.2956700570E-05 + 1.4373368282E-04 1.1231824189E-04 1.2852879734E-04 + -1.7600011100E-04 3.9645225012E-05 5.9756397129E-05 + 2.3899985912E-04 -2.8464216231E-04 -6.2896445856E-04 + -2.5430509405E-04 -8.6265366268E-06 -2.1737700277E-04 + 1.1519207254E-04 -1.3459990108E-04 9.6056306652E-05 + -3.1609082523E-04 5.6864019317E-05 3.5422807201E-05 + 2.5000332492E-04 2.3649789555E-04 -6.4653346351E-05 + -7.3301679237E-04 1.7348791644E-06 1.4224774465E-04 + 2.0597923978E-04 -1.6964469429E-04 -4.1719690909E-04 + -6.6358662158E-05 -1.9616134469E-04 4.4337093263E-04 + 3.8320967771E-04 -8.6236212454E-05 7.6423444428E-06 + -2.1644625401E-04 1.6601266073E-04 2.2298316065E-04 + 3.8052277281E-05 1.9667627064E-05 -7.2746623760E-05 + -2.9163594835E-04 -3.7381746453E-04 -4.7005724472E-04 + 3.1226779824E-04 3.0879467671E-04 2.1156527826E-04 + 1.1922508311E-04 2.1109352441E-05 2.6327484174E-04 :F: - -4.3366934383E-04 -6.1939645027E-03 -1.5104090760E-03 - 1.0705590218E-02 -1.1810980709E-04 -7.0597454681E-03 - -2.2729584712E-02 8.3634507706E-03 -6.9523577082E-03 - 1.1277377212E-02 -1.1855576977E-03 1.1184033699E-02 - -2.2257699437E-03 -6.6117963818E-03 -5.2545610361E-04 - -3.3239762511E-03 2.1234507927E-04 -5.2204893761E-04 - 1.1440897491E-02 5.3200733362E-03 -1.9533324385E-03 - 1.5634875907E-03 1.9060212316E-03 8.2634487413E-04 - -2.5904970984E-02 -1.2297787932E-03 -1.0744362389E-02 - 1.6611510959E-02 -6.2382558555E-03 2.1618390470E-02 - 1.9603953979E-03 1.6272048860E-03 4.3461108114E-03 - 9.9348415671E-03 1.7258440486E-04 -4.3682515584E-03 - -7.7345552880E-03 1.0164745458E-03 1.4497981054E-04 - -5.1797600992E-03 -5.2735740398E-03 4.6001538152E-03 - 1.3527428234E-02 -7.8150261025E-03 -3.2052973647E-03 - 2.8364191525E-04 2.1136919332E-03 3.0612694704E-03 - 1.1896449033E-02 -8.9329977026E-04 -4.3095262926E-03 - -7.5026408937E-03 1.5713556847E-03 1.0276818274E-02 - 8.3770370714E-04 -5.0922505441E-03 -1.1895897064E-02 - -1.8569097854E-02 1.1627577088E-02 2.6917635492E-03 - 1.7681531458E-02 -2.8936113185E-03 2.3887930663E-03 - 1.7669792942E-03 1.4392461069E-03 1.4683893774E-02 - -5.8644716933E-05 -2.6960420751E-03 -1.3400435390E-02 - -1.2578723021E-02 -2.2858420463E-03 4.7309108057E-03 - -3.8305619973E-04 4.1268357089E-03 -1.0739077679E-02 - -9.4022610397E-03 9.6149461912E-04 3.5128007511E-03 - 1.3077572002E-02 6.6505267488E-05 -3.6458263303E-03 - -2.6693606222E-03 -5.0681563872E-03 1.1070520459E-02 - 9.1566496225E-03 6.7384038471E-03 -1.1418394953E-02 - -2.5156957220E-02 8.3242390240E-03 -2.2864253698E-03 - 1.3503665683E-02 1.9025993228E-04 -8.9738473223E-03 - -1.3726931971E-03 -2.1824981447E-03 8.3739078158E-03 -:LATVEC_SCALE: 1.5399454402E+01 1.5399454402E+01 1.5399454402E+01 + -2.4226114262E-03 -4.8609918837E-03 -1.2031375794E-03 + 1.0603549243E-02 5.3507827746E-04 -5.4167576673E-03 + -1.4375980960E-02 3.4630518489E-03 -6.3941499720E-03 + 8.3039240473E-03 -1.2150771218E-03 8.2983317764E-03 + -1.5577926748E-03 -6.2014851111E-03 -3.8905513100E-04 + -3.3005489024E-03 1.2260482010E-03 1.1978106982E-03 + 1.0052884719E-02 4.1790513893E-03 5.4521721349E-04 + 6.4807169344E-05 8.1558338427E-04 -1.3360910442E-03 + -2.1563588226E-02 2.4332407389E-04 -7.9536317937E-03 + 1.2928647889E-02 -2.5325492077E-03 1.4823522222E-02 + 1.5031834247E-03 -7.6731017373E-05 1.7413477976E-03 + 6.1864182216E-03 5.7403462575E-04 -1.2193970309E-03 + -2.6805002035E-03 2.4376260810E-03 5.1884953286E-04 + -6.2371199348E-03 -5.2972531863E-03 1.2909418427E-03 + 8.4917162066E-03 -5.5172104438E-03 -6.0964688035E-04 + -1.8621419598E-03 -1.1155535634E-03 2.4358409557E-03 + 8.7066683915E-03 -2.3317066313E-03 -2.1058596705E-03 + -4.9512542309E-03 5.1573195930E-04 1.1120865732E-02 + 1.9467188372E-03 -3.1943932579E-03 -1.4037602728E-02 + -1.6535826639E-02 1.0402000038E-02 1.2004718629E-03 + 2.0684149012E-02 -2.8801701905E-03 1.4702493508E-03 + -3.8938434225E-04 -6.4718453423E-05 1.5212361086E-02 + 4.0607813389E-03 -1.4735156342E-03 -1.6498829120E-02 + -2.0947294068E-02 3.2899011862E-03 6.1440619487E-03 + 2.7538471737E-03 3.6050189554E-03 -1.1997740070E-02 + -1.0697470616E-02 -8.7953652414E-04 9.4978562003E-03 + 1.3848778694E-02 2.1574591242E-03 -4.1900048232E-03 + -1.8793790678E-03 -2.5828783666E-03 1.0543383772E-02 + 1.0081018438E-02 4.3250672322E-03 -1.3520098889E-02 + -2.4660514252E-02 2.5390691970E-03 -1.8000296202E-03 + 1.8118895888E-02 6.6780315346E-04 -8.6045507430E-03 + -4.2745811899E-03 -7.5207813397E-04 1.1235470771E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5580271851E+03 +:LATVEC_SCALE: + 1.5266392385E+01 1.5266392385E+01 1.5266392385E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0739851500E+00 -2.9938366353E-02 4.7049322843E-02 - -2.9938366353E-02 -6.7483132666E-01 -1.6414951993E-01 - 4.7049322843E-02 -1.6414951993E-01 -8.9717025520E-01 + 1.0592359492E+00 5.3570759957E-03 -4.4243719552E-03 + 5.3570759957E-03 7.7521636322E-01 1.7199067221E-01 + -4.4243719552E-03 1.7199067221E-01 8.9079223266E-01 :STRESS: - -1.7788573122E+00 -4.4063412458E-01 1.6170148643E+00 - -4.4063412458E-01 1.3668675546E+00 4.7169547945E-02 - 1.6170148643E+00 4.7169547945E-02 -4.0020685421E-01 -:PRESIO: 8.8199557730E-01 -:PRES: 2.7073220393E-01 -:PRESIG: 9.1339834639E-01 + -2.7334444010E+00 -3.3440397089E-01 1.2986230649E+00 + -3.3440397089E-01 1.4535831601E+00 3.9342511142E-02 + 1.2986230649E+00 3.9342511142E-02 -1.8021985902E+00 +:CONSTRESS: + 3.7418709665E+00 6.6784269884E-01 -2.5643594697E+00 + 6.6784269884E-01 -5.3509179818E+00 2.6476220157E-01 + -2.5643594697E+00 2.6476220157E-01 1.6090470154E+00 +:TOTSTRESS: + 5.0809383721E-02 -3.2808165195E-01 1.2613120328E+00 + -3.2808165195E-01 4.6725511850E+00 -1.3211404050E-01 + 1.2613120328E+00 -1.3211404050E-01 1.0839438075E+00 +:PRESIO: 9.0841484837E-01 +:PRES: 1.0273532770E+00 +:CONPRES: 6.8448497935E-14 +:TOTPRES: 1.9357681254E+00 +:PRESIG: 9.3771855315E-01 :MIND: -Al - Al: 4.8697704605E+00 -Si - Si: 4.7221805117E+00 -Al - Si: 4.6965753645E+00 -:MDSTEP: 35 -:MDTM: 2.91 +Al - Al: 4.6973534451E+00 +Si - Si: 4.7550155939E+00 +Al - Si: 4.8651030560E+00 + + +:MDSTEP: 25 +:MDTM: 13.72 :TWIST: 0 :TEL: 1120 -:TIO: 1119.41019153804 -:TEN: -3.2410996504E+00 -:KEN: 5.1512716548E-03 -:KENIG: 5.3174417082E-03 -:FEN: -3.2462509221E+00 -:UEN: -3.2455212804E+00 -:TSEN: -7.2964171145E-04 -:NPT_NP_HAMIL: -2.5966761747E-05 +:TIO: 1119.57534863485 +:TEN: -3.2408345004E+00 +:KEN: 5.1520316703E-03 +:KENIG: 5.3182262403E-03 +:FEN: -3.2459865321E+00 +:UEN: -3.2451353964E+00 +:TSEN: -8.5113572323E-04 +:NPT_NP_HAMIL: -9.9575567130E-05 +:SNOSE[0]: 1.0089100772E+00 +:SNOSE[1]: 3.8791236747E-05 :R: - 3.5194847608E-01 4.5618086674E-01 2.6718939254E-01 - 3.9317346144E+00 1.5382202294E+01 4.1528357621E+00 - 8.0555657724E+00 1.5202156534E+01 7.2465522057E-02 - 1.1393838772E+01 1.5384862121E+01 3.6154487370E+00 - 1.7451968732E-01 7.9758279643E+00 1.5391355148E+01 - 3.7282675649E+00 7.9782035924E+00 3.8180205606E+00 - 7.2524197717E+00 7.4020580109E+00 1.7843570065E-01 - 1.1577748073E+01 7.8272008511E+00 4.0802182715E+00 - 5.6725542482E-01 1.5180174085E+01 7.7722230931E+00 - 3.6356945274E+00 3.5444130798E-02 1.1235767139E+01 - 7.7287959529E+00 5.7445986462E-02 7.8093627098E+00 - 1.1646583053E+01 1.5186688758E+01 1.1838187288E+01 - 3.3818406771E-01 7.7342693528E+00 7.9432624057E+00 - 4.3010365616E+00 7.9416369610E+00 1.1523666028E+01 - 7.2975173328E+00 8.0831334090E+00 7.5374825950E+00 - 1.1577382093E+01 7.2232940799E+00 1.1531333681E+01 - 1.1571434238E-01 3.9591304430E+00 3.9659307700E+00 - 3.7085526272E+00 3.8884090060E+00 2.3718941131E-02 - 7.9038715343E+00 3.6093820411E+00 3.3437433044E+00 - 1.1374255725E+01 3.8304986055E+00 1.5232006250E+01 - 3.6093674900E-01 1.1451659726E+01 3.9458113452E+00 - 3.5907006818E+00 1.1617354190E+01 5.0862467436E-01 - 7.9038496319E+00 1.1770679231E+01 3.8456943685E+00 - 1.0986910987E+01 1.1551950200E+01 9.6745501962E-02 - 1.6946649833E-01 3.7017922859E+00 1.1225416164E+01 - 3.8188890915E+00 3.6865668558E+00 8.0595901650E+00 - 8.0117392010E+00 3.7734672989E+00 1.1582413151E+01 - 1.1380667414E+01 3.9997806769E+00 7.8908609410E+00 - 3.1329436918E-01 1.1576831394E+01 1.1538852058E+01 - 3.6522772578E+00 1.1244982387E+01 7.8086377570E+00 - 7.9331191947E+00 1.1831620430E+01 1.1776968987E+01 - 1.1687522599E+01 1.1581280712E+01 7.9004666142E+00 + 3.7178175294E-01 3.2929740759E-01 1.9008127419E-01 + 3.8613341732E+00 1.5259081886E+01 4.0401284607E+00 + 7.9070013282E+00 1.5128101952E+01 1.4816930108E-01 + 1.1332953295E+01 1.5263715358E+01 3.6408503312E+00 + 1.2498855438E-01 7.8408490334E+00 1.5267751632E+01 + 3.7364572866E+00 7.8336436696E+00 3.7940179246E+00 + 7.3058521738E+00 7.4202787514E+00 1.2452546523E-01 + 1.1475149288E+01 7.7266264958E+00 3.9842487393E+00 + 5.4922324073E-01 1.5116909577E+01 7.6978267758E+00 + 3.6487598476E+00 2.7357710785E-02 1.1212688396E+01 + 7.6539792228E+00 4.1373851824E-02 7.8007988755E+00 + 1.1514964984E+01 1.5120376012E+01 1.1660116355E+01 + 2.4202374903E-01 7.6583480990E+00 7.8081222498E+00 + 4.1469159749E+00 7.8155195710E+00 1.1435169075E+01 + 7.3404840548E+00 7.9157071162E+00 7.5208601293E+00 + 1.1478066465E+01 7.3006631842E+00 1.1438765388E+01 + 7.2412835757E-02 3.8990662952E+00 3.9031211945E+00 + 3.7245629597E+00 3.8447000997E+00 6.7439052030E-04 + 7.7764168597E+00 3.6509463205E+00 3.4787187457E+00 + 1.1351611332E+01 3.7919529192E+00 1.5153149078E+01 + 3.1633156489E-01 1.1388108930E+01 3.8871328081E+00 + 3.6368143750E+00 1.1503119195E+01 4.8571321193E-01 + 7.7730082278E+00 1.1613349253E+01 3.8393735524E+00 + 1.1085213824E+01 1.1452166033E+01 5.6539487303E-02 + 1.1592941657E-01 3.7087179089E+00 1.1239950374E+01 + 3.8097940351E+00 3.7026811103E+00 7.8760961303E+00 + 7.8391766028E+00 3.7611214434E+00 1.1484498247E+01 + 1.1337972275E+01 3.9278787760E+00 7.7604185827E+00 + 2.9461336053E-01 1.1469118385E+01 1.1466634315E+01 + 3.7095189030E+00 1.1236189692E+01 7.8591122949E+00 + 7.7769454483E+00 1.1654866338E+01 1.1631007624E+01 + 1.1560757713E+01 1.1477509724E+01 7.7612674994E+00 :V: - -9.2600480195E-05 4.7893315875E-04 2.9560234740E-04 - 1.7092590285E-04 -3.4665851802E-05 2.9441746658E-04 - 2.7257403748E-04 -2.0934712273E-04 -3.2090631055E-04 - -1.2317625318E-04 -4.5220948645E-05 -2.0185395698E-04 - 1.8719566546E-04 2.5241880964E-04 -3.3970363892E-05 - -1.6798292838E-04 3.0762940987E-04 -3.4758663040E-05 - -4.3786459627E-04 -3.1517114876E-04 2.0652042707E-04 - 1.6460957009E-05 1.3811991151E-04 2.4578407356E-04 - -2.1081869638E-06 -2.6881953389E-04 8.5016209739E-06 - -1.4161395827E-04 1.8979461064E-05 -2.4856419771E-04 - 3.7876820438E-05 6.5438985101E-05 -2.2428911034E-04 - 1.4734219719E-04 -2.5498885194E-04 2.9924007484E-04 - 3.5865733445E-04 4.2695228418E-05 2.6895206003E-04 - 4.5790056080E-04 2.2084294512E-04 -3.2826387235E-05 - -3.9500153304E-04 3.7701785864E-04 -1.9779436239E-04 - 5.3968884582E-07 -5.5472653193E-04 -1.8062763721E-05 - 1.9382204306E-04 1.0208250527E-04 1.0805372677E-04 - -2.0559136519E-04 4.4322030996E-05 1.1384784260E-04 - 2.4065034273E-04 -2.9992387568E-04 -6.8151528857E-04 - -3.3836482344E-04 4.8164001389E-05 -2.0213109155E-04 - 2.0790823375E-04 -1.4538074772E-04 1.0481188952E-04 - -3.0476989825E-04 6.0697937194E-05 1.0774315854E-04 - 2.5458947622E-04 2.2088890861E-04 -1.3782026959E-04 - -8.0272354566E-04 2.3689737217E-06 1.6767431084E-04 - 2.0901687256E-04 -1.4590003577E-04 -4.6713697389E-04 - -1.1551062482E-04 -1.9048418375E-04 4.6863779336E-04 - 4.4483823741E-04 -7.8286485402E-05 -1.3114203837E-05 - -2.2434632417E-04 1.4165081424E-04 2.7585605052E-04 - 8.4442793494E-05 4.7792195182E-05 -1.3285177248E-04 - -4.1012769648E-04 -3.3602120600E-04 -4.7446704312E-04 - 3.8598372160E-04 3.0344343506E-04 1.6195558938E-04 - 1.0241707821E-04 1.4059813390E-05 3.0648677096E-04 + -8.6856435966E-05 5.1636985262E-04 3.0566851824E-04 + 1.2077463797E-04 -3.6943412458E-05 3.3304548141E-04 + 3.7297679101E-04 -2.4345495084E-04 -2.9184318725E-04 + -1.7634773352E-04 -4.0045522456E-05 -2.5469937184E-04 + 2.0072114074E-04 2.9015978453E-04 -3.3102235434E-05 + -1.5337911474E-04 3.1162466205E-04 -3.7080952645E-05 + -5.0207306151E-04 -3.4589962620E-04 2.1343286080E-04 + 1.2912094929E-05 1.3352901215E-04 2.5335053388E-04 + 1.2157216253E-04 -2.7091090773E-04 5.7350882045E-05 + -2.2007823298E-04 4.1846982424E-05 -3.4796142428E-04 + 2.7689324487E-05 6.3705904269E-05 -2.4349464598E-04 + 1.0858818562E-04 -2.6229943670E-04 3.2061717761E-04 + 3.9223171849E-04 3.5799090020E-05 2.7192902531E-04 + 4.9560961328E-04 2.5276485225E-04 -4.9615231541E-05 + -4.6130717999E-04 4.1840702367E-04 -1.9242586911E-04 + 6.0071646744E-06 -5.6901277704E-04 -3.1654643230E-05 + 1.4777877750E-04 1.1101204878E-04 1.2721701904E-04 + -1.7811881763E-04 3.9841650826E-05 6.5014472881E-05 + 2.3943315315E-04 -2.8571449208E-04 -6.3453775033E-04 + -2.6190464730E-04 -3.5184454852E-06 -2.1636792146E-04 + 1.2498386574E-04 -1.3576744683E-04 9.6633165845E-05 + -3.1562621905E-04 5.6754019816E-05 4.2742495403E-05 + 2.5138679521E-04 2.3531455242E-04 -7.2466290633E-05 + -7.4162913716E-04 3.2403251206E-06 1.4488913928E-04 + 2.0685931235E-04 -1.6756082811E-04 -4.2222364849E-04 + -7.1410530735E-05 -1.9620535137E-04 4.4699552580E-04 + 3.8920918910E-04 -8.5064934478E-05 5.6156674269E-06 + -2.1696265020E-04 1.6439923333E-04 2.2773896116E-04 + 4.2830618798E-05 2.1792065744E-05 -7.9116045003E-05 + -3.0308959401E-04 -3.7176952952E-04 -4.7008994191E-04 + 3.2038379645E-04 3.0855237213E-04 2.0703613238E-04 + 1.1701275364E-04 2.0669965070E-05 2.6814859834E-04 :F: - -2.7527468243E-04 -6.1756145868E-03 -1.5408913027E-03 - 1.0605457266E-02 -1.8463361213E-04 -7.1405008798E-03 - -2.3467451575E-02 8.9743240085E-03 -6.9026281042E-03 - 1.1420091223E-02 -1.1490399827E-03 1.1380523530E-02 - -2.2087319697E-03 -6.5609921625E-03 -5.8155400774E-04 - -3.2214354631E-03 3.2790821255E-05 -7.3987636437E-04 - 1.1423826836E-02 5.3190804723E-03 -2.2280772939E-03 - 1.7364513714E-03 1.9923185074E-03 1.1451529275E-03 - -2.6048015107E-02 -1.3853559272E-03 -1.0860246118E-02 - 1.6804742637E-02 -6.5794269493E-03 2.2107994125E-02 - 2.0117926176E-03 1.8090377179E-03 4.5453076958E-03 - 1.0308768931E-02 1.2596298786E-04 -4.6253657010E-03 - -8.2551688712E-03 7.4488723264E-04 1.2411971773E-04 - -4.9868322618E-03 -5.1302798706E-03 4.8767731878E-03 - 1.3836934926E-02 -7.9430507861E-03 -3.4943069743E-03 - 5.8735815964E-04 2.4789353604E-03 3.1348928309E-03 - 1.2121811163E-02 -7.6148212772E-04 -4.4992245883E-03 - -7.7528502746E-03 1.6755202496E-03 1.0135752911E-02 - 9.2506365579E-04 -5.2306383125E-03 -1.1734762951E-02 - -1.8695132360E-02 1.1599206928E-02 2.9132112246E-03 - 1.7208291825E-02 -2.8337653416E-03 2.3743590990E-03 - 1.8851228314E-03 1.5808323925E-03 1.4617097746E-02 - -3.8703165308E-04 -2.7994768443E-03 -1.3038959977E-02 - -1.1645643898E-02 -2.9044118334E-03 4.6680923885E-03 - -7.1964951117E-04 4.1263000552E-03 -1.0526992994E-02 - -9.2378724542E-03 1.2135044638E-03 2.8949201329E-03 - 1.2859579531E-02 -2.3065961548E-04 -3.5669680133E-03 - -2.7507574809E-03 -5.2737119606E-03 1.0837874088E-02 - 9.1667844782E-03 6.8961283544E-03 -1.1239978955E-02 - -2.5043464956E-02 8.8249945570E-03 -2.0850992285E-03 - 1.2877682571E-02 9.1307404232E-05 -9.0852249341E-03 - -1.0844475048E-03 -2.3425916005E-03 8.1345867830E-03 -:LATVEC_SCALE: 1.5418529745E+01 1.5418529745E+01 1.5418529745E+01 + -2.1398848524E-03 -5.0197487457E-03 -1.2502698874E-03 + 1.0682953124E-02 4.2674246327E-04 -5.5725170119E-03 + -1.5099985849E-02 3.7610196957E-03 -6.4523591313E-03 + 8.5826075784E-03 -1.2520821192E-03 8.5632721190E-03 + -1.6416522972E-03 -6.2322257705E-03 -3.7841049687E-04 + -3.3791349463E-03 1.2973234907E-03 1.0482319768E-03 + 1.0179499573E-02 4.2868152432E-03 3.2301531826E-04 + 2.0796244860E-04 9.5851738964E-04 -1.1331791458E-03 + -2.1984168262E-02 8.9322811903E-05 -8.2707779475E-03 + 1.3294937792E-02 -2.8692543661E-03 1.5458069693E-02 + 1.4760963806E-03 1.1766171929E-04 2.0366213315E-03 + 6.4950840374E-03 4.6334700280E-04 -1.4964284455E-03 + -3.0993823998E-03 2.4345590961E-03 4.8259978492E-04 + -6.1417344142E-03 -5.3245519329E-03 1.5921618102E-03 + 8.9451065278E-03 -5.7205691546E-03 -8.8200416212E-04 + -1.6616675195E-03 -9.5437052308E-04 2.4839991523E-03 + 9.1350932038E-03 -2.1834832956E-03 -2.3047945163E-03 + -5.1845578958E-03 6.0706454847E-04 1.1073790198E-02 + 1.7203750284E-03 -3.4709775154E-03 -1.3928852323E-02 + -1.6860598791E-02 1.0635748442E-02 1.2620029950E-03 + 2.0678236377E-02 -3.0006577644E-03 1.6672585240E-03 + -1.7304459237E-04 5.6591751490E-05 1.5309302878E-02 + 3.6188706218E-03 -1.5588207984E-03 -1.6290682777E-02 + -2.0393400745E-02 2.9442787819E-03 5.8868507445E-03 + 2.5000083332E-03 3.6730515541E-03 -1.2047546152E-02 + -1.0696970283E-02 -8.4255184883E-04 8.9600892991E-03 + 1.3948914928E-02 2.0050815626E-03 -4.1239129980E-03 + -1.9537047821E-03 -2.7798200494E-03 1.0857247651E-02 + 9.9611149555E-03 4.6068864052E-03 -1.3368531204E-02 + -2.4953466839E-02 2.9870489592E-03 -2.0256643534E-03 + 1.7867048032E-02 7.5555828177E-04 -8.4480316750E-03 + -3.9305544724E-03 -8.9750531503E-04 1.0969448752E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5721141439E+03 +:LATVEC_SCALE: + 1.5286513446E+01 1.5286513446E+01 1.5286513446E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0772359078E+00 -3.2307655644E-02 4.9858213174E-02 - -3.2307655644E-02 -6.6493183467E-01 -1.6294455677E-01 - 4.9858213174E-02 -1.6294455677E-01 -8.9807452924E-01 + 1.0600201674E+00 7.9388426974E-03 -9.5484733368E-03 + 7.9388426974E-03 7.6489834571E-01 1.7108374161E-01 + -9.5484733368E-03 1.7108374161E-01 8.9083801266E-01 :STRESS: - -1.6185283952E+00 -4.5523875879E-01 1.6315602025E+00 - -4.5523875879E-01 1.4145382793E+00 4.9163965197E-02 - 1.6315602025E+00 4.9163965197E-02 -2.2379230741E-01 -:PRESIO: 8.8008075725E-01 -:PRES: 1.4259414110E-01 -:PRESIG: 9.1052155180E-01 + -2.4910520250E+00 -3.4189438225E-01 1.3249408222E+00 + -3.4189438225E-01 1.5143772131E+00 3.8201484979E-02 + 1.3249408222E+00 3.8201484979E-02 -1.4990038764E+00 +:CONSTRESS: + 3.6650377891E+00 6.8716576996E-01 -2.6283100976E+00 + 6.8716576996E-01 -5.0761582636E+00 2.6548245459E-01 + -2.6283100976E+00 2.6548245459E-01 1.4111204745E+00 +:TOTSTRESS: + -1.1396559672E-01 -3.3733254502E-01 1.2938208021E+00 + -3.3733254502E-01 4.3266793963E+00 -1.3260019796E-01 + 1.2938208021E+00 -1.3260019796E-01 9.7872141452E-01 +:PRESIO: 9.0525217524E-01 +:PRES: 8.2522622945E-01 +:CONPRES: 1.8208629548E-13 +:TOTPRES: 1.7304784047E+00 +:PRESIG: 9.3445385832E-01 :MIND: -Al - Al: 4.8713630550E+00 -Si - Si: 4.7194366112E+00 -Al - Si: 4.6816002140E+00 -:MDSTEP: 36 -:MDTM: 1.38 +Al - Al: 4.6904342284E+00 +Si - Si: 4.7548384539E+00 +Al - Si: 4.8602402791E+00 + + +:MDSTEP: 26 +:MDTM: 34.50 :TWIST: 0 :TEL: 1120 -:TIO: 1121.15552431068 -:TEN: -3.2411121851E+00 -:KEN: 5.1593032802E-03 -:KENIG: 5.3257324182E-03 -:FEN: -3.2462714884E+00 -:UEN: -3.2455457121E+00 -:TSEN: -7.2577628433E-04 -:NPT_NP_HAMIL: -2.4999488833E-05 +:TIO: 1119.4870718202 +:TEN: -3.2408687509E+00 +:KEN: 5.1516254404E-03 +:KENIG: 5.3178069063E-03 +:FEN: -3.2460203763E+00 +:UEN: -3.2451863890E+00 +:TSEN: -8.3398735459E-04 +:NPT_NP_HAMIL: -1.0551205908E-04 +:SNOSE[0]: 1.0098108689E+00 +:SNOSE[1]: 4.9785426767E-05 :R: - 3.5008518646E-01 4.6854069467E-01 2.7482860352E-01 - 3.9409710416E+00 1.5400380824E+01 4.1651852708E+00 - 8.0720005052E+00 1.5215896496E+01 6.4513913764E-02 - 1.1405031461E+01 1.5402770234E+01 3.6150624381E+00 - 1.7934852687E-01 7.9918757260E+00 1.5409557286E+01 - 3.7286779991E+00 7.9957053555E+00 3.8218756387E+00 - 7.2506853621E+00 7.4034739768E+00 1.8374819104E-01 - 1.1592508838E+01 7.8403381945E+00 4.0913758963E+00 - 5.6757966994E-01 1.5192283049E+01 7.7819185708E+00 - 3.6368944028E+00 3.5876234884E-02 1.1243789516E+01 - 7.7393267874E+00 5.9161889848E-02 7.8135260595E+00 - 1.1664780633E+01 1.5199167532E+01 1.1860200761E+01 - 3.4739029869E-01 7.7449105683E+00 7.9597632795E+00 - 4.3176490542E+00 7.9568775469E+00 1.1537177315E+01 - 7.2969314545E+00 8.1023854268E+00 7.5418656841E+00 - 1.1591733363E+01 7.2185148772E+00 1.1545198661E+01 - 1.2080785809E-01 3.9665524751E+00 3.9734643489E+00 - 3.7079535325E+00 3.8943409324E+00 2.6692234071E-02 - 7.9196316317E+00 3.6063520580E+00 3.3308470472E+00 - 1.1379722510E+01 3.8365732787E+00 1.5245884834E+01 - 3.6674407943E-01 1.1462196747E+01 3.9533222133E+00 - 3.5876129103E+00 1.1633257857E+01 5.1210067969E-01 - 7.9199394832E+00 1.1790691081E+01 3.8468815307E+00 - 1.0980471900E+01 1.1566273111E+01 1.0107783299E-01 - 1.7484898300E-01 3.7028071991E+00 1.1227604660E+01 - 3.8206417655E+00 3.6864227331E+00 8.0812182980E+00 - 8.0328378132E+00 3.7761946882E+00 1.1596381995E+01 - 1.1389160064E+01 4.0081796984E+00 7.9075967139E+00 - 3.1588553464E-01 1.1592428818E+01 1.1549706627E+01 - 3.6463305422E+00 1.1250677786E+01 7.8065166304E+00 - 7.9526617515E+00 1.1853788894E+01 1.1795452217E+01 - 1.1704515293E+01 1.1595936483E+01 7.9179411201E+00 + 3.7010998395E-01 3.4252698311E-01 1.9791688892E-01 + 3.8695718643E+00 1.5278607243E+01 4.0537739271E+00 + 7.9267582843E+00 1.5142345677E+01 1.4108179997E-01 + 1.1343809588E+01 1.5283159396E+01 3.6394575263E+00 + 1.3012900011E-01 7.8585167973E+00 1.5287378927E+01 + 3.7376332602E+00 7.8518818278E+00 3.7981860504E+00 + 7.3032372988E+00 7.4216575762E+00 1.2999318380E-01 + 1.1490842376E+01 7.7402976052E+00 3.9958685614E+00 + 5.5283957615E-01 1.5130433674E+01 7.7095102558E+00 + 3.6482667980E+00 2.8415328199E-02 1.1219165986E+01 + 7.6649285809E+00 4.3011634352E-02 7.8052157340E+00 + 1.1533126113E+01 1.5134120891E+01 1.1683685925E+01 + 2.5206646782E-01 7.6695106506E+00 7.8253355985E+00 + 4.1647368972E+00 7.8322306850E+00 1.1449264909E+01 + 7.3389199356E+00 7.9366623480E+00 7.5261516149E+00 + 1.1493580327E+01 7.2963097453E+00 1.1453317530E+01 + 7.6233676474E-02 3.9070321417E+00 3.9114940633E+00 + 3.7250987612E+00 3.8508429595E+00 2.3560090773E-03 + 7.7927882900E+00 3.6487225424E+00 3.4675411412E+00 + 1.1360213361E+01 3.7970089400E+00 1.5168082887E+01 + 3.1998263708E-01 1.1399974813E+01 3.8947488453E+00 + 3.6338488844E+00 1.1519937250E+01 4.8751707923E-01 + 7.7896832834E+00 1.1634738365E+01 3.8426193805E+00 + 1.1081527653E+01 1.1467604620E+01 6.0247787981E-02 + 1.2123543318E-01 3.7095478821E+00 1.1244451543E+01 + 3.8130600952E+00 3.7027646815E+00 7.8977977714E+00 + 7.8594241345E+00 3.7640597037E+00 1.1499996604E+01 + 1.1347761465E+01 3.9372050729E+00 7.7765332047E+00 + 2.9613126680E-01 1.1485050263E+01 1.1479949510E+01 + 3.7068130077E+00 1.1242028871E+01 7.8579566570E+00 + 7.7954244593E+00 1.1678143256E+01 1.1651676887E+01 + 1.1579125037E+01 1.1493391878E+01 7.7783871824E+00 :V: - -9.2622494482E-05 4.7521931514E-04 2.9445388136E-04 - 1.7605245273E-04 -3.4715184949E-05 2.9045003453E-04 - 2.6041042322E-04 -2.0456316873E-04 -3.2397887487E-04 - -1.1726893430E-04 -4.5742747043E-05 -1.9586746646E-04 - 1.8584736348E-04 2.4879617039E-04 -3.4220497272E-05 - -1.6939393895E-04 3.0725844016E-04 -3.5087548625E-05 - -4.3155901839E-04 -3.1209500400E-04 2.0513803986E-04 - 1.7314853437E-05 1.3894944518E-04 2.4605128734E-04 - -1.5225614959E-05 -2.6917871997E-04 3.0207322880E-06 - -1.3297122895E-04 1.5641573646E-05 -2.3711556890E-04 - 3.8842427914E-05 6.6267750333E-05 -2.2171717982E-04 - 1.5234901433E-04 -2.5460422514E-04 2.9653341274E-04 - 3.5404754133E-04 4.3016641124E-05 2.6867580912E-04 - 4.5481198546E-04 2.1798071163E-04 -3.0328665380E-05 - -3.8753449034E-04 3.7254214910E-04 -1.9930526508E-04 - 8.3485456107E-07 -5.5277919445E-04 -1.6461002893E-05 - 1.9944363309E-04 1.0158544341E-04 1.0574045581E-04 - -2.0908399727E-04 4.5076985207E-05 1.1860911658E-04 - 2.4079485951E-04 -3.0207719324E-04 -6.8633529439E-04 - -3.4698516926E-04 5.3716173043E-05 -2.0046679137E-04 - 2.1597342118E-04 -1.4656888268E-04 1.0582881852E-04 - -3.0347380594E-04 6.1386445215E-05 1.1468063778E-04 - 2.5408151454E-04 2.1925601722E-04 -1.4395620564E-04 - -8.0734775454E-04 9.6054936788E-07 1.6972199316E-04 - 2.0840536028E-04 -1.4371955169E-04 -4.7164256987E-04 - -1.1983532140E-04 -1.8965703936E-04 4.6944835059E-04 - 4.5050065563E-04 -7.8299492579E-05 -1.4823735696E-05 - -2.2539482773E-04 1.3892045157E-04 2.8075301639E-04 - 8.8772223358E-05 5.1069022661E-05 -1.3812344263E-04 - -4.2172959910E-04 -3.3132755667E-04 -4.7487838681E-04 - 3.9172903225E-04 3.0310540510E-04 1.5735526580E-04 - 1.0176331249E-04 1.2908527352E-05 3.1003703819E-04 + -8.7672237027E-05 5.1265505412E-04 3.0434679340E-04 + 1.2590220095E-04 -3.6672989732E-05 3.2946012099E-04 + 3.6435716560E-04 -2.4093571233E-04 -2.9445614902E-04 + -1.7156310631E-04 -4.0594112483E-05 -2.4975218053E-04 + 1.9942945370E-04 2.8636933130E-04 -3.3217330628E-05 + -1.5475607185E-04 3.1159783562E-04 -3.6511646031E-05 + -4.9580052966E-04 -3.4294570476E-04 2.1306211559E-04 + 1.3025267822E-05 1.3374876638E-04 2.5227073951E-04 + 1.1012688437E-04 -2.7030307988E-04 5.2981261245E-05 + -2.1280194348E-04 4.0222783375E-05 -3.3924176356E-04 + 2.8365266977E-05 6.3673840887E-05 -2.4185345072E-04 + 1.1169730537E-04 -2.6150890945E-04 3.1907887869E-04 + 3.8968886849E-04 3.6940272662E-05 2.7155673834E-04 + 4.9144063253E-04 2.4951713083E-04 -4.8625011111E-05 + -4.5566188549E-04 4.1454269077E-04 -1.9251055556E-04 + 5.2098746742E-06 -5.6818189314E-04 -3.0321474963E-05 + 1.5196880572E-04 1.0974535244E-04 1.2576929459E-04 + -1.8028928254E-04 4.0070103868E-05 7.0214062103E-05 + 2.3968565284E-04 -2.8682246519E-04 -6.3983513386E-04 + -2.6955627755E-04 1.6868366010E-06 -2.1525888347E-04 + 1.3470063251E-04 -1.3694341685E-04 9.7265776937E-05 + -3.1495838084E-04 5.6684031050E-05 5.0075836418E-05 + 2.5247377531E-04 2.3401423181E-04 -8.0135617281E-05 + -7.4969952755E-04 4.5679141076E-06 1.4735936352E-04 + 2.0754469813E-04 -1.6539506151E-04 -4.2711673353E-04 + -7.6422794987E-05 -1.9616282184E-04 4.5020211964E-04 + 3.9511025840E-04 -8.3946478952E-05 3.6242569300E-06 + -2.1744445066E-04 1.6264033991E-04 2.3254745527E-04 + 4.7529291252E-05 2.4040645731E-05 -8.5371161091E-05 + -3.1455274824E-04 -3.6938584932E-04 -4.7006702189E-04 + 3.2824559318E-04 3.0824840949E-04 2.0251841380E-04 + 1.1493181051E-04 2.0153386657E-05 2.7279543827E-04 :F: - -1.2980612249E-04 -6.1322719886E-03 -1.5695324710E-03 - 1.0487772549E-02 -2.4798929287E-04 -7.2143469970E-03 - -2.4195303048E-02 9.6082869790E-03 -6.8367708310E-03 - 1.1534233289E-02 -1.1085103937E-03 1.1560939713E-02 - -2.1774708835E-03 -6.5030210000E-03 -6.4356277605E-04 - -3.0983218699E-03 -1.7267944102E-04 -9.5941014811E-04 - 1.1396719600E-02 5.3011165916E-03 -2.5005633808E-03 - 1.9106867228E-03 2.0769080810E-03 1.4716319923E-03 - -2.6150137232E-02 -1.5335287684E-03 -1.0946744115E-02 - 1.6971200486E-02 -6.9093736215E-03 2.2566953072E-02 - 2.0747463852E-03 1.9870489537E-03 4.7337073087E-03 - 1.0684959578E-02 8.3563687922E-05 -4.8748074002E-03 - -8.7820880668E-03 4.4248249766E-04 1.0959906340E-04 - -4.7972698338E-03 -4.9713158271E-03 5.1358335929E-03 - 1.4118558115E-02 -8.0525143919E-03 -3.7858321436E-03 - 9.0010167838E-04 2.8564379919E-03 3.2135051218E-03 - 1.2338178150E-02 -6.3781031744E-04 -4.6836135225E-03 - -8.0043333390E-03 1.7767600226E-03 9.9944145857E-03 - 1.0436052185E-03 -5.3526512263E-03 -1.1588407048E-02 - -1.8802764116E-02 1.1545322007E-02 3.1544891437E-03 - 1.6697795731E-02 -2.7534604991E-03 2.3414009332E-03 - 1.9924537509E-03 1.7236874808E-03 1.4547525629E-02 - -6.9976162210E-04 -2.9012781925E-03 -1.2666302509E-02 - -1.0707891324E-02 -3.5331298677E-03 4.6212144444E-03 - -1.0573414461E-03 4.1171828749E-03 -1.0311396426E-02 - -9.0730401280E-03 1.4847624834E-03 2.2817248038E-03 - 1.2619958304E-02 -5.3792700923E-04 -3.4900744551E-03 - -2.8320969060E-03 -5.4818739535E-03 1.0567918922E-02 - 9.1939783847E-03 7.0322199718E-03 -1.1076760871E-02 - -2.4889473015E-02 9.3181354190E-03 -1.8428462366E-03 - 1.2231434403E-02 -2.2240611119E-05 -9.2196472266E-03 - -7.9928339287E-04 -2.5023386405E-03 7.9097602319E-03 -:LATVEC_SCALE: 1.5437614888E+01 1.5437614888E+01 1.5437614888E+01 + -1.8677393629E-03 -5.1596249136E-03 -1.2926274026E-03 + 1.0742660839E-02 3.2012435562E-04 -5.7149744915E-03 + -1.5820251505E-02 4.0862980187E-03 -6.5035382020E-03 + 8.8524097033E-03 -1.2801733931E-03 8.8239210518E-03 + -1.7105088437E-03 -6.2490928010E-03 -3.7142038356E-04 + -3.4445513603E-03 1.3532844937E-03 8.8409033277E-04 + 1.0280948201E-02 4.3801053613E-03 9.3732376915E-05 + 3.5542717748E-04 1.0952135956E-03 -9.1241206496E-04 + -2.2379007704E-02 -7.2935519219E-05 -8.5694308019E-03 + 1.3645299539E-02 -3.2083992485E-03 1.6080759350E-02 + 1.4524983172E-03 3.1847189311E-04 2.3244400485E-03 + 6.8089394045E-03 3.5451333712E-04 -1.7737723563E-03 + -3.5252252500E-03 2.4128510442E-03 4.4537173177E-04 + -6.0247701186E-03 -5.3329203679E-03 1.8998171817E-03 + 9.3854346842E-03 -5.9191600831E-03 -1.1564406027E-03 + -1.4507637871E-03 -7.8158283429E-04 2.5287317054E-03 + 9.5407161531E-03 -2.0289330353E-03 -2.5060819318E-03 + -5.4250150971E-03 7.0383426692E-04 1.1012323121E-02 + 1.5283741423E-03 -3.7387324489E-03 -1.3806538400E-02 + -1.7171429460E-02 1.0842431544E-02 1.3283599905E-03 + 2.0627382394E-02 -3.1092762451E-03 1.8367676465E-03 + 2.5874777163E-05 1.7672699799E-04 1.5389260385E-02 + 3.1887203282E-03 -1.6475015242E-03 -1.6070419015E-02 + -1.9788239426E-02 2.5722361597E-03 5.6559709892E-03 + 2.2377281703E-03 3.7337391036E-03 -1.2061604616E-02 + -1.0673885354E-02 -7.8872549715E-04 8.4084110394E-03 + 1.4021613024E-02 1.8337109980E-03 -4.0539454993E-03 + -2.0353798122E-03 -2.9745357936E-03 1.1110940121E-02 + 9.8507116234E-03 4.8857491083E-03 -1.3209522484E-02 + -2.5209031909E-02 3.4391543765E-03 -2.2087492268E-03 + 1.7572736573E-02 8.2987429409E-04 -8.3148590433E-03 + -3.5916760611E-03 -1.0467252432E-03 1.0703439449E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5864881595E+03 +:LATVEC_SCALE: + 1.5306990070E+01 1.5306990070E+01 1.5306990070E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0803372126E+00 -3.4567509851E-02 5.2400965783E-02 - -3.4567509851E-02 -6.5487151992E-01 -1.6157752846E-01 - 5.2400965783E-02 -1.6157752846E-01 -8.9865518263E-01 + 1.0602713289E+00 1.0519739109E-02 -1.4417699812E-02 + 1.0519739109E-02 7.5407725428E-01 1.7006346640E-01 + -1.4417699812E-02 1.7006346640E-01 8.9031039157E-01 :STRESS: - -1.4639498661E+00 -4.7039146114E-01 1.6436195738E+00 - -4.7039146114E-01 1.4622379455E+00 5.1608198715E-02 - 1.6436195738E+00 5.1608198715E-02 -6.3555248092E-02 -:PRESIO: 8.7795463839E-01 -:PRES: 2.1755722878E-02 -:PRESIG: 9.0856314332E-01 + -2.2531249136E+00 -3.5011421724E-01 1.3497386198E+00 + -3.5011421724E-01 1.5817432728E+00 3.7342104165E-02 + 1.3497386198E+00 3.7342104165E-02 -1.2001366671E+00 +:CONSTRESS: + 3.5956668754E+00 7.0784007110E-01 -2.6886760513E+00 + 7.0784007110E-01 -4.8150668780E+00 2.6551524069E-01 + -2.6886760513E+00 2.6551524069E-01 1.2194000025E+00 +:TOTSTRESS: + -2.8227063299E-01 -3.4720611475E-01 1.3245197317E+00 + -3.4720611475E-01 3.9874008594E+00 -1.3279387846E-01 + 1.3245197317E+00 -1.3279387846E-01 8.7104705614E-01 +:PRESIO: 9.0155299158E-01 +:PRES: 6.2383943594E-01 +:CONPRES: 4.5388664165E-14 +:TOTPRES: 1.5253924275E+00 +:PRESIG: 9.3063534615E-01 :MIND: -Al - Al: 4.8734394392E+00 -Si - Si: 4.7164884790E+00 -Al - Si: 4.6669362147E+00 -:MDSTEP: 37 -:MDTM: 1.36 +Al - Al: 4.6841612311E+00 +Si - Si: 4.7545061573E+00 +Al - Si: 4.8438441081E+00 + + +:MDSTEP: 27 +:MDTM: 13.74 :TWIST: 0 :TEL: 1120 -:TIO: 1122.628102788 -:TEN: -3.2411242202E+00 -:KEN: 5.1660797521E-03 -:KENIG: 5.3327274861E-03 -:FEN: -3.2462903000E+00 -:UEN: -3.2455667944E+00 -:TSEN: -7.2350553271E-04 -:NPT_NP_HAMIL: -2.3856571510E-05 +:TIO: 1118.83069848562 +:TEN: -3.2409030067E+00 +:KEN: 5.1486049593E-03 +:KENIG: 5.3146889903E-03 +:FEN: -3.2460516116E+00 +:UEN: -3.2452335645E+00 +:TSEN: -8.1804711256E-04 +:NPT_NP_HAMIL: -1.0267422082E-04 +:SNOSE[0]: 1.0110073983E+00 +:SNOSE[1]: 5.5683794560E-05 :R: - 3.4822080230E-01 4.8081943195E-01 2.8244545281E-01 - 3.9503339930E+00 1.5418544698E+01 4.1774389100E+00 - 8.0881243963E+00 1.5229746588E+01 5.6479600349E-02 - 1.1416360531E+01 1.5420653030E+01 3.6148195279E+00 - 1.8414841522E-01 8.0078339211E+00 1.5427739813E+01 - 3.7290482990E+00 8.0131961606E+00 3.8257160864E+00 - 7.2490915188E+00 7.4049531818E+00 1.8902752286E-01 - 1.1607284409E+01 7.8534942630E+00 4.1025466457E+00 - 5.6757679178E-01 1.5204363470E+01 7.7914712224E+00 - 3.6383047246E+00 3.6221825219E-02 1.1252087315E+01 - 7.7498772594E+00 6.0902010891E-02 7.8177444634E+00 - 1.1683101459E+01 1.5211637841E+01 1.1882141627E+01 - 3.5648345857E-01 7.7555509813E+00 7.9762570829E+00 - 4.3341943532E+00 7.9720480011E+00 1.1550744168E+01 - 7.2965197447E+00 8.1215273626E+00 7.5461973686E+00 - 1.1606086952E+01 7.2137705747E+00 1.1559095057E+01 - 1.2604770481E-01 3.9739629213E+00 3.9809377241E+00 - 3.7072572774E+00 3.9002908060E+00 2.9784485416E-02 - 7.9353960901E+00 3.6032576312E+00 3.3178149950E+00 - 1.1384957762E+01 3.8427831574E+00 1.5259791283E+01 - 3.7274975387E-01 1.1472693147E+01 3.9608572398E+00 - 3.5845489119E+00 1.1649172736E+01 5.1574997138E-01 - 7.9360126488E+00 1.1810657132E+01 3.8479148902E+00 - 1.0973902744E+01 1.1580544688E+01 1.0546411082E-01 - 1.8021684403E-01 3.7038699327E+00 1.1229664766E+01 - 3.8222835926E+00 3.6862952321E+00 8.1028635651E+00 - 8.0540778878E+00 3.7789133858E+00 1.1610300136E+01 - 1.1397611882E+01 4.0165086193E+00 7.9244508686E+00 - 3.1858608211E-01 1.1608101313E+01 1.1560420497E+01 - 3.6400858094E+00 1.1256479255E+01 7.8043714552E+00 - 7.9723416735E+00 1.1875945357E+01 1.1813814315E+01 - 1.1721488505E+01 1.1610553170E+01 7.9355018322E+00 + 3.6842461463E-01 3.5568595871E-01 2.0573265592E-01 + 3.8780201147E+00 1.5298450208E+01 4.0674224255E+00 + 7.9464700725E+00 1.5156956567E+01 1.3392318173E-01 + 1.1355013253E+01 1.5302901189E+01 3.6382560510E+00 + 1.3524563349E-01 7.8762598566E+00 1.5307315259E+01 + 3.7388464966E+00 7.8702897311E+00 3.8024439026E+00 + 7.3009132117E+00 7.4232518298E+00 1.3545934126E-01 + 1.1506774740E+01 7.7541374476E+00 4.0075523403E+00 + 5.5618412540E-01 1.5144273340E+01 7.7212428283E+00 + 3.6480247132E+00 2.9432321350E-02 1.1226083184E+01 + 7.6760522733E+00 4.4652673725E-02 7.8098275621E+00 + 1.1551605719E+01 1.5148186545E+01 1.1707464299E+01 + 2.6206032122E-01 7.6808594422E+00 7.8427077909E+00 + 4.1825551401E+00 7.8490289652E+00 1.1463620075E+01 + 7.3376351011E+00 7.9576953612E+00 7.5315875095E+00 + 1.1509311096E+01 7.2921102204E+00 1.1468136501E+01 + 8.0167037056E-02 3.9150507495E+00 3.9199136372E+00 + 3.7256500788E+00 3.8570720799E+00 4.1684144883E-03 + 7.8093315182E+00 3.6465357068E+00 3.4562845601E+00 + 1.1368848065E+01 3.8022730945E+00 1.5183348540E+01 + 3.2388506593E-01 1.1412040043E+01 3.9024642264E+00 + 3.6309660459E+00 1.1536991745E+01 4.8951484177E-01 + 7.8065497291E+00 1.1656339824E+01 3.8457524921E+00 + 1.1077849123E+01 1.1483308722E+01 6.4021651063E-02 + 1.2656560280E-01 3.7105028878E+00 1.1249048497E+01 + 3.8162776789E+00 3.7029195044E+00 7.9197508191E+00 + 7.8799912292E+00 3.7670991855E+00 1.1515681428E+01 + 1.1357763894E+01 3.9465720303E+00 7.7929347845E+00 + 2.9777256812E-01 1.1501275360E+01 1.1493342842E+01 + 3.7038875834E+00 1.1248148852E+01 7.8569471531E+00 + 7.8142661491E+00 1.1701661341E+01 1.1672479411E+01 + 1.1597683191E+01 1.1509496132E+01 7.7957879382E+00 :V: - -9.2511206743E-05 4.7122633964E-04 2.9310232730E-04 - 1.8099587354E-04 -3.4773812922E-05 2.8626473091E-04 - 2.4773483705E-04 -1.9933662950E-04 -3.2680243096E-04 - -1.1123941344E-04 -4.6213499482E-05 -1.8967461851E-04 - 1.8439690444E-04 2.4504835335E-04 -3.4479185225E-05 - -1.7063048912E-04 3.0658559099E-04 -3.5503568691E-05 - -4.2499937873E-04 -3.0883147168E-04 2.0348816184E-04 - 1.8243601697E-05 1.3972991090E-04 2.4632284141E-04 - -2.8359563914E-05 -2.6943732748E-04 -2.4952023727E-06 - -1.2417500218E-04 1.2133830178E-05 -2.2530405443E-04 - 3.9812705384E-05 6.7141585319E-05 -2.1891160644E-04 - 1.5743689305E-04 -2.5407664282E-04 2.9351414354E-04 - 3.4895181877E-04 4.3157339044E-05 2.6821862365E-04 - 4.5152991514E-04 2.1506266045E-04 -2.7685646779E-05 - -3.7968873371E-04 3.6777839771E-04 -2.0083084211E-04 - 1.2863394471E-06 -5.5028724565E-04 -1.4812056312E-05 - 2.0502985798E-04 1.0108328887E-04 1.0327388887E-04 - -2.1255605688E-04 4.5850239447E-05 1.2321608103E-04 - 2.4084034548E-04 -3.0408960556E-04 -6.9063045946E-04 - -3.5541621420E-04 5.9196880878E-05 -1.9855904661E-04 - 2.2363636928E-04 -1.4762091366E-04 1.0675927334E-04 - -3.0193157380E-04 6.2102932925E-05 1.2149690901E-04 - 2.5325859770E-04 2.1743489117E-04 -1.4980691867E-04 - -8.1098634991E-04 -7.4985028508E-07 1.7163308956E-04 - 2.0749662577E-04 -1.4145447747E-04 -4.7572960199E-04 - -1.2399438485E-04 -1.8857736279E-04 4.6965653979E-04 - 4.5574438994E-04 -7.8410312071E-05 -1.6483214438E-05 - -2.2633456831E-04 1.3600458515E-04 2.8532811723E-04 - 9.3049006729E-05 5.4372310923E-05 -1.4321660031E-04 - -4.3296154951E-04 -3.2618962024E-04 -4.7486398615E-04 - 3.9689695732E-04 3.0251664063E-04 1.5259671460E-04 - 1.0118273283E-04 1.1673818385E-05 3.1327085048E-04 + -8.8324503782E-05 5.0872485864E-04 3.0291360614E-04 + 1.3100372269E-04 -3.6444991561E-05 3.2571251036E-04 + 3.5528301487E-04 -2.3817702158E-04 -2.9699541931E-04 + -1.6660358645E-04 -4.1140756542E-05 -2.4460913689E-04 + 1.9804799632E-04 2.8249383179E-04 -3.3319595322E-05 + -1.5611086075E-04 3.1149852467E-04 -3.6018098917E-05 + -4.8934403587E-04 -3.3984907019E-04 2.1250917289E-04 + 1.3209182824E-05 1.3399364011E-04 2.5123072692E-04 + 9.8482757330E-05 -2.6969647894E-04 4.8460015961E-05 + -2.0530466063E-04 3.8418744786E-05 -3.3012734305E-04 + 2.9020121061E-05 6.3724364948E-05 -2.3999839994E-04 + 1.1492343893E-04 -2.6069350696E-04 3.1730560788E-04 + 3.8681543350E-04 3.8051310523E-05 2.7108233567E-04 + 4.8719284352E-04 2.4620052619E-04 -4.7466261981E-05 + -4.4967087373E-04 4.1046058286E-04 -1.9267414838E-04 + 4.5215329269E-06 -5.6708660711E-04 -2.8960122020E-05 + 1.5629253524E-04 1.0852349896E-04 1.2418809472E-04 + -1.8251656783E-04 4.0333139674E-05 7.5346343808E-05 + 2.3977924922E-04 -2.8796566819E-04 -6.4485987271E-04 + -2.7725315690E-04 6.9728342301E-06 -2.1405144247E-04 + 1.4431725485E-04 -1.3812365423E-04 9.7942832723E-05 + -3.1410203146E-04 5.6654626020E-05 5.7410884475E-05 + 2.5327484011E-04 2.3260065998E-04 -8.7652230466E-05 + -7.5721447814E-04 5.7046491687E-06 1.4967220164E-04 + 2.0803583244E-04 -1.6315530852E-04 -4.3186473626E-04 + -8.1383559696E-05 -1.9602892922E-04 4.5299182750E-04 + 4.0090308058E-04 -8.2891921211E-05 1.6714560304E-06 + -2.1789880519E-04 1.6074166904E-04 2.3738056340E-04 + 5.2151657345E-05 2.6409936334E-05 -9.1506565541E-05 + -3.2600578656E-04 -3.6667419251E-04 -4.6997656871E-04 + 3.3583441116E-04 3.0788185164E-04 1.9800761267E-04 + 1.1298284980E-04 1.9558854378E-05 2.7721786330E-04 :F: - 2.4265952685E-06 -6.0635817645E-03 -1.5968256360E-03 - 1.0352531931E-02 -3.0860213491E-04 -7.2820043488E-03 - -2.4910922910E-02 1.0263089642E-02 -6.7543915129E-03 - 1.1617751884E-02 -1.0645859507E-03 1.1723888412E-02 - -2.1314124640E-03 -6.4387785162E-03 -7.1112393552E-04 - -2.9551002761E-03 -4.0430276908E-04 -1.1797288040E-03 - 1.1361188054E-02 5.2653609643E-03 -2.7687552412E-03 - 2.0855406586E-03 2.1610821582E-03 1.8038742872E-03 - -2.6210427590E-02 -1.6728344424E-03 -1.1003217045E-02 - 1.7110175453E-02 -7.2260528121E-03 2.2993292448E-02 - 2.1506936141E-03 2.1613532788E-03 4.9121581330E-03 - 1.1062940794E-02 4.6074487194E-05 -5.1157714102E-03 - -9.3144998679E-03 1.0898797721E-04 1.0228983278E-04 - -4.6134947763E-03 -4.7981585490E-03 5.3749076613E-03 - 1.4371051183E-02 -8.1419552764E-03 -4.0797867594E-03 - 1.2221278014E-03 3.2437005723E-03 3.2977903034E-03 - 1.2548742902E-02 -5.2272436891E-04 -4.8613717325E-03 - -8.2569861153E-03 1.8749003369E-03 9.8550337344E-03 - 1.1911616296E-03 -5.4571837475E-03 -1.1459439274E-02 - -1.8892558923E-02 1.1466496020E-02 3.4135736448E-03 - 1.6151819227E-02 -2.6522425373E-03 2.2895108572E-03 - 2.0883272829E-03 1.8673276968E-03 1.4478363106E-02 - -9.9689663964E-04 -3.0006944293E-03 -1.2282986115E-02 - -9.7700637453E-03 -4.1697453449E-03 4.5900488021E-03 - -1.3965344613E-03 4.0989909884E-03 -1.0094834452E-02 - -8.9097234829E-03 1.7749932933E-03 1.6749842727E-03 - 1.2361466844E-02 -8.5434438205E-04 -3.4165156160E-03 - -2.9139911605E-03 -5.6950880878E-03 1.0265704814E-02 - 9.2375240914E-03 7.1456851560E-03 -1.0931847386E-02 - -2.4693494680E-02 9.8031745064E-03 -1.5609618098E-03 - 1.1569024252E-02 -1.4920778117E-04 -9.3774775533E-03 - -5.1838710433E-04 -2.6611341835E-03 7.7016183222E-03 -:LATVEC_SCALE: 1.5456688147E+01 1.5456688147E+01 1.5456688147E+01 + -1.6062052289E-03 -5.2791138707E-03 -1.3307137515E-03 + 1.0783074609E-02 2.1571355746E-04 -5.8451277004E-03 + -1.6537727333E-02 4.4389861034E-03 -6.5469544185E-03 + 9.1111175883E-03 -1.2995248414E-03 9.0802878314E-03 + -1.7648406176E-03 -6.2532849340E-03 -3.6943836640E-04 + -3.4946556362E-03 1.3928420153E-03 7.0789252826E-04 + 1.0359006295E-02 4.4592828476E-03 -1.4162977201E-04 + 5.0593980901E-04 1.2249728908E-03 -6.7494352433E-04 + -2.2746463200E-02 -2.4250639539E-04 -8.8489490169E-03 + 1.3979310269E-02 -3.5491527626E-03 1.6690389393E-02 + 1.4336716030E-03 5.2363810592E-04 2.6035625011E-03 + 7.1265848538E-03 2.4769728511E-04 -2.0511693538E-03 + -3.9563342600E-03 2.3711634460E-03 4.0789442537E-04 + -5.8891910063E-03 -5.3216710210E-03 2.2108077574E-03 + 9.8103150740E-03 -6.1115414141E-03 -1.4330585041E-03 + -1.2302381450E-03 -5.9611042370E-04 2.5711995586E-03 + 9.9236626677E-03 -1.8700264492E-03 -2.7095391434E-03 + -5.6717519306E-03 8.0357513034E-04 1.0936812252E-02 + 1.3731965259E-03 -3.9949935475E-03 -1.3674037864E-02 + -1.7468354771E-02 1.1022793098E-02 1.4037972953E-03 + 2.0532700185E-02 -3.2053501214E-03 1.9818219684E-03 + 2.0909445312E-04 2.9625458094E-04 1.5452766683E-02 + 2.7714073880E-03 -1.7398403083E-03 -1.5837773326E-02 + -1.9137963667E-02 2.1744737904E-03 5.4495079234E-03 + 1.9698760773E-03 3.7882507778E-03 -1.2043422800E-02 + -1.0631440009E-02 -7.1590187943E-04 7.8455929566E-03 + 1.4065939990E-02 1.6444849726E-03 -3.9793229642E-03 + -2.1236137382E-03 -3.1664396261E-03 1.1304357033E-02 + 9.7529160372E-03 5.1587177610E-03 -1.3044783094E-02 + -2.5427630066E-02 3.8927177940E-03 -2.3486603167E-03 + 1.7236924999E-02 8.8883081046E-04 -8.2044369714E-03 + -3.2583288169E-03 -1.1989373724E-03 1.0437270780E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6011214652E+03 +:LATVEC_SCALE: + 1.5327779944E+01 1.5327779944E+01 1.5327779944E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0821717182E+00 -3.6664453490E-02 5.4634540025E-02 - -3.6664453490E-02 -6.4400332503E-01 -1.5987757579E-01 - 5.4634540025E-02 -1.5987757579E-01 -8.9799192185E-01 + 1.0600416047E+00 1.3085593877E-02 -1.9016998336E-02 + 1.3085593877E-02 7.4281415483E-01 1.6892589226E-01 + -1.9016998336E-02 1.6892589226E-01 8.8923338060E-01 :STRESS: - -1.3148437723E+00 -4.8597083035E-01 1.6532547062E+00 - -4.8597083035E-01 1.5093954839E+00 5.4460347744E-02 - 1.6532547062E+00 5.4460347744E-02 7.9933709090E-02 -:PRESIO: 8.7472232169E-01 -:PRES: -9.1495140231E-02 -:PRESIG: 9.0639278047E-01 + -2.0203484146E+00 -3.5908733365E-01 1.3727511889E+00 + -3.5908733365E-01 1.6549081018E+00 3.6783683237E-02 + 1.3727511889E+00 3.6783683237E-02 -9.0750090774E-01 +:CONSTRESS: + 3.5333767430E+00 7.2997832358E-01 -2.7452389947E+00 + 7.2997832358E-01 -4.5689875554E+00 2.6473900176E-01 + -2.7452389947E+00 2.6473900176E-01 1.0356108124E+00 +:TOTSTRESS: + -4.5298672372E-01 -3.5780539606E-01 1.3534708075E+00 + -3.5780539606E-01 3.6568936084E+00 -1.3259679274E-01 + 1.3534708075E+00 -1.3259679274E-01 7.6112347597E-01 +:PRESIO: 8.9736304671E-01 +:PRES: 4.2431374018E-01 +:CONPRES: 1.6979214779E-13 +:TOTPRES: 1.3216767869E+00 +:PRESIG: 9.2631024176E-01 :MIND: -Al - Al: 4.8760008281E+00 -Si - Si: 4.7133388344E+00 -Al - Si: 4.6526111656E+00 -:MDSTEP: 38 -:MDTM: 1.36 +Al - Al: 4.6785389944E+00 +Si - Si: 4.7540110474E+00 +Al - Si: 4.8276401554E+00 + + +:MDSTEP: 28 +:MDTM: 13.93 :TWIST: 0 :TEL: 1120 -:TIO: 1122.67612176258 -:TEN: -3.2411413328E+00 -:KEN: 5.1663007245E-03 -:KENIG: 5.3329555866E-03 -:FEN: -3.2463076335E+00 -:UEN: -3.2455848673E+00 -:TSEN: -7.2276624241E-04 -:NPT_NP_HAMIL: -2.2559339958E-05 +:TIO: 1118.1338525807 +:TEN: -3.2409348080E+00 +:KEN: 5.1453982326E-03 +:KENIG: 5.3113788208E-03 +:FEN: -3.2460802063E+00 +:UEN: -3.2452767894E+00 +:TSEN: -8.0341689868E-04 +:NPT_NP_HAMIL: -9.3229545437E-05 +:SNOSE[0]: 1.0122643360E+00 +:SNOSE[1]: 5.1628280736E-05 :R: - 3.4635812044E-01 4.9300997497E-01 2.9003464462E-01 - 3.9598149603E+00 1.5436678758E+01 4.1895872572E+00 - 8.1039168916E+00 1.5243703325E+01 4.8368846709E-02 - 1.1427817634E+01 1.5438496844E+01 3.6147214760E+00 - 1.8891681429E-01 8.0236917124E+00 1.5445887473E+01 - 3.7293793944E+00 8.0306604308E+00 3.8295360155E+00 - 7.2476374755E+00 7.4064928962E+00 1.9426692411E-01 - 1.1622065401E+01 7.8666602335E+00 4.1137267332E+00 - 5.6724615842E-01 1.5216403182E+01 7.8008729140E+00 - 3.6399255463E+00 3.6476773391E-02 1.1260658364E+01 - 7.7604401437E+00 6.2667376437E-02 7.8220160321E+00 - 1.1701536310E+01 1.5224088527E+01 1.1903990688E+01 - 3.6545103461E-01 7.7661782060E+00 7.9927316896E+00 - 4.3506633586E+00 7.9871393496E+00 1.1564358768E+01 - 7.2962842414E+00 8.1405443963E+00 7.5504699022E+00 - 1.1620435595E+01 7.2090678004E+00 1.1573012917E+01 - 1.3143290549E-01 3.9813576936E+00 3.9883432832E+00 - 3.7064607006E+00 3.9062552719E+00 3.2991940092E-02 - 7.9511551162E+00 3.6000989227E+00 3.3046566297E+00 - 1.1389955200E+01 3.8491225265E+00 1.5273717054E+01 - 3.7894314237E-01 1.1483141394E+01 3.9684102302E+00 - 3.5815111789E+00 1.1665088240E+01 5.1956915677E-01 - 7.9520538123E+00 1.1830561274E+01 3.8487978149E+00 - 1.0967217200E+01 1.1594746095E+01 1.0990107350E-01 - 1.8556252083E-01 3.7049789071E+00 1.1231595888E+01 - 3.8238148830E+00 3.6861872679E+00 8.1245032826E+00 - 8.0754411087E+00 3.7816171873E+00 1.1624157484E+01 - 1.1406014475E+01 4.0247588495E+00 7.9414074353E+00 - 3.2139466147E-01 1.1623838050E+01 1.1570986576E+01 - 3.6335490127E+00 1.1262386846E+01 7.8022056623E+00 - 7.9921368211E+00 1.1898071928E+01 1.1832039554E+01 - 1.1738432619E+01 1.1625117438E+01 7.9531334726E+00 + 3.6672822383E-01 3.6876991971E-01 2.1352635657E-01 + 3.8866676604E+00 1.5318565677E+01 4.0810594598E+00 + 7.9661037109E+00 1.5171896379E+01 1.2669373968E-01 + 1.1366535456E+01 1.5322896724E+01 3.6372395028E+00 + 1.4033664372E-01 7.8940545267E+00 1.5327516829E+01 + 3.7400862735E+00 7.8888440575E+00 3.8067784837E+00 + 7.2988616844E+00 7.4250424419E+00 1.4091978242E-01 + 1.1522915165E+01 7.7681248501E+00 4.0192905837E+00 + 5.5925057929E-01 1.5158384000E+01 7.7329987359E+00 + 3.6480279260E+00 3.0404229926E-02 1.1233416461E+01 + 7.6873278913E+00 4.6299161205E-02 7.8146163227E+00 + 1.1570374083E+01 1.5162529135E+01 1.1731413181E+01 + 2.7199771182E-01 7.6923717187E+00 7.8602147861E+00 + 4.2003585856E+00 7.8658911276E+00 1.1478205706E+01 + 7.3366154182E+00 7.9787793846E+00 7.5371434766E+00 + 1.1525228481E+01 7.2880481832E+00 1.1483189979E+01 + 8.4216581874E-02 3.9231123922E+00 3.9283657625E+00 + 3.7262040106E+00 3.8633774205E+00 6.1102697720E-03 + 7.8260213101E+00 3.6443734115E+00 3.4449433125E+00 + 1.1377480489E+01 3.8077364811E+00 1.5198904149E+01 + 3.2803598956E-01 1.1424271260E+01 3.9102690908E+00 + 3.6281588453E+00 1.1554250768E+01 4.9170545963E-01 + 7.8235791149E+00 1.1678118171E+01 3.8487651636E+00 + 1.1074157387E+01 1.1499240528E+01 6.7857767951E-02 + 1.3191551339E-01 3.7115735111E+00 1.1253710952E+01 + 3.8194367735E+00 3.7031365848E+00 7.9419239192E+00 + 7.9008540854E+00 3.7702270925E+00 1.1531520587E+01 + 1.1367946748E+01 3.9559654214E+00 7.8096022269E+00 + 2.9953491895E-01 1.1517763774E+01 1.1506783790E+01 + 3.7007309094E+00 1.1254524160E+01 7.8560613722E+00 + 7.8334425426E+00 1.1725386505E+01 1.1693382336E+01 + 1.1616402486E+01 1.1525787541E+01 7.8134429868E+00 :V: - -9.2274567765E-05 4.6697695849E-04 2.9155318625E-04 - 1.8574302400E-04 -3.4840561410E-05 2.8187311600E-04 - 2.3457321523E-04 -1.9366661929E-04 -3.2936852999E-04 - -1.0511213935E-04 -4.6631427083E-05 -1.8329435514E-04 - 1.8285547329E-04 2.4118580056E-04 -3.4749168146E-05 - -1.7168281088E-04 3.0560202537E-04 -3.6006671929E-05 - -4.1820272452E-04 -3.0539688279E-04 2.0157753904E-04 - 1.9246287157E-05 1.4046144395E-04 2.4660343169E-04 - -4.1472296484E-05 -2.6959317875E-04 -8.0239140204E-06 - -1.1525189993E-04 8.4679569684E-06 -2.1316415879E-04 - 4.0793277333E-05 6.8057974220E-05 -2.1588351678E-04 - 1.6260135959E-04 -2.5340690284E-04 2.9019378307E-04 - 3.4337825351E-04 4.3102339556E-05 2.6758752903E-04 - 4.4806010871E-04 2.1210171180E-04 -2.4911398581E-05 - -3.7149330159E-04 3.6274676059E-04 -2.0237207399E-04 - 1.8978455340E-06 -5.4725518772E-04 -1.3115441926E-05 - 2.1057261097E-04 1.0057343669E-04 1.0066169892E-04 - -2.1600555539E-04 4.6639655787E-05 1.2766522557E-04 - 2.4080312552E-04 -3.0595309697E-04 -6.9441104410E-04 - -3.6364208354E-04 6.4587719267E-05 -1.9640406510E-04 - 2.3087305283E-04 -1.4852701929E-04 1.0759406237E-04 - -3.0015399407E-04 6.2847330478E-05 1.2818477157E-04 - 2.5213234075E-04 2.1543140980E-04 -1.5536176666E-04 - -8.1364422407E-04 -2.7630790725E-06 1.7341458495E-04 - 2.0629368652E-04 -1.3911356746E-04 -4.7939757606E-04 - -1.2798470324E-04 -1.8723966843E-04 4.6927085857E-04 - 4.6055863003E-04 -7.8623661038E-05 -1.8092387985E-05 - -2.2716686380E-04 1.3290618869E-04 2.8956319384E-04 - 9.7276491602E-05 5.7687283377E-05 -1.4813524641E-04 - -4.4379353682E-04 -3.2062191087E-04 -4.7440994897E-04 - 4.0147798136E-04 3.0167470156E-04 1.4767648557E-04 - 1.0067472368E-04 1.0358049661E-05 3.1619565877E-04 + -8.8839898320E-05 5.0471267909E-04 3.0144347556E-04 + 1.3609797477E-04 -3.6266819162E-05 3.2188815180E-04 + 3.4584572921E-04 -2.3522332949E-04 -2.9952578444E-04 + -1.6151767311E-04 -4.1690575442E-05 -2.3933389890E-04 + 1.9663197051E-04 2.7860837820E-04 -3.3419524809E-05 + -1.5747193449E-04 3.1139201642E-04 -3.5614678937E-05 + -4.8283447348E-04 -3.3669904352E-04 2.1182179028E-04 + 1.3468359812E-05 1.3429161394E-04 2.5029857871E-04 + 8.6683906379E-05 -2.6915836071E-04 4.3811409944E-05 + -1.9764803682E-04 3.6444939364E-05 -3.2070906284E-04 + 2.9662693779E-05 6.3873943491E-05 -2.3799231854E-04 + 1.1829366830E-04 -2.5991427032E-04 3.1537423859E-04 + 3.8370209327E-04 3.9130310737E-05 2.7057049092E-04 + 4.8299235263E-04 2.4288499064E-04 -4.6149736948E-05 + -4.4345232948E-04 4.0626373603E-04 -1.9296294257E-04 + 3.9479437424E-06 -5.6585559567E-04 -2.7579386922E-05 + 1.6077324667E-04 1.0737414193E-04 1.2250300920E-04 + -1.8484557487E-04 4.0641341053E-05 8.0420083547E-05 + 2.3978920730E-04 -2.8920593391E-04 -6.4975862397E-04 + -2.8504978119E-04 1.2325248029E-05 -2.1279181777E-04 + 1.5384224369E-04 -1.3933368790E-04 9.8675613108E-05 + -3.1313962920E-04 5.6678594107E-05 6.4749512745E-05 + 2.5385692672E-04 2.3112829279E-04 -9.5027552083E-05 + -7.6432992924E-04 6.6401071879E-06 1.5187376514E-04 + 2.0838010526E-04 -1.6088454957E-04 -4.3655288554E-04 + -8.6301203915E-05 -1.9584147339E-04 4.5546677471E-04 + 4.0666602790E-04 -8.1929641412E-05 -2.3932279855E-07 + -2.1837971070E-04 1.5874434383E-04 2.4226275792E-04 + 5.6714280901E-05 2.8901355550E-05 -9.7538796111E-05 + -3.3750231632E-04 -3.6372282005E-04 -4.6990895641E-04 + 3.4320689538E-04 3.0751827014E-04 1.9354210422E-04 + 1.1119082697E-04 1.8889916369E-05 2.8148022003E-04 :F: - 1.2167525130E-04 -5.9698580615E-03 -1.6230496273E-03 - 1.0199597851E-02 -3.6716232467E-04 -7.3439507271E-03 - -2.5611254179E-02 1.0935345636E-02 -6.6560297341E-03 - 1.1669009301E-02 -1.0180119158E-03 1.1867969297E-02 - -2.0694627827E-03 -6.3691587139E-03 -7.8381864355E-04 - -2.7922779947E-03 -6.6212753550E-04 -1.3999609534E-03 - 1.1318504408E-02 5.2105505994E-03 -3.0307475530E-03 - 2.2602855179E-03 2.2460460047E-03 2.1401689573E-03 - -2.6228268547E-02 -1.8017990577E-03 -1.1029174052E-02 - 1.7220764418E-02 -7.5269879586E-03 2.3385221725E-02 - 2.2413202163E-03 2.3321607128E-03 5.0817180074E-03 - 1.1441948584E-02 1.4216403685E-05 -5.3470767344E-03 - -9.8508750339E-03 -2.5531292865E-04 1.0342852265E-04 - -4.4384564128E-03 -4.6126421746E-03 5.5914693076E-03 - 1.4593835981E-02 -8.2100440033E-03 -4.3757854329E-03 - 1.5533830769E-03 3.6378842237E-03 3.3876192706E-03 - 1.2756835102E-02 -4.1680260600E-04 -5.0310558179E-03 - -8.5108979875E-03 1.9701703587E-03 9.7196449015E-03 - 1.3647591279E-03 -5.5425641735E-03 -1.1349398317E-02 - -1.8964727341E-02 1.1363445118E-02 3.6874920527E-03 - 1.5572469927E-02 -2.5296367180E-03 2.2181305818E-03 - 2.1715146413E-03 2.0119869408E-03 1.4412458126E-02 - -1.2785568337E-03 -3.0968461590E-03 -1.1888970037E-02 - -8.8365425282E-03 -4.8110095828E-03 4.5744031090E-03 - -1.7377808774E-03 4.0712155060E-03 -9.8791437088E-03 - -8.7492365250E-03 2.0834503835E-03 1.0762385343E-03 - 1.2086928363E-02 -1.1790472747E-03 -3.3479134655E-03 - -2.9977750141E-03 -5.9157034220E-03 9.9365271246E-03 - 9.2966370037E-03 7.2356822498E-03 -1.0808028240E-02 - -2.4454894339E-02 1.0278882976E-02 -1.2411448854E-03 - 1.0894775014E-02 -2.8774691561E-04 -9.5592682794E-03 - -2.4323738562E-04 -2.8185755876E-03 7.5120266909E-03 -:LATVEC_SCALE: 1.5475734526E+01 1.5475734526E+01 1.5475734526E+01 + -1.3568103537E-03 -5.3761391484E-03 -1.3651155908E-03 + 1.0804416105E-02 1.1391120559E-04 -5.9625083626E-03 + -1.7250755797E-02 4.8189118032E-03 -6.5812840751E-03 + 9.3561484742E-03 -1.3104501178E-03 9.3296772996E-03 + -1.8038175627E-03 -6.2453862900E-03 -3.7296133048E-04 + -3.5291790752E-03 1.4150972336E-03 5.2070579858E-04 + 1.0414162728E-02 4.5240957422E-03 -3.8340561592E-04 + 6.6003014485E-04 1.3478873352E-03 -4.2105343815E-04 + -2.3083599521E-02 -4.1777958388E-04 -9.1071987638E-03 + 1.4294468911E-02 -3.8896887826E-03 1.7283699407E-02 + 1.4189356978E-03 7.3100816039E-04 2.8727277187E-03 + 7.4478166183E-03 1.4276017345E-04 -2.3265989007E-03 + -4.3937382401E-03 2.3081866027E-03 3.7137196859E-04 + -5.7374842583E-03 -5.2903856512E-03 2.5242369307E-03 + 1.0218285519E-02 -6.2961004825E-03 -1.7117880667E-03 + -1.0008254518E-03 -3.9782623122E-04 2.6111221040E-03 + 1.0283332420E-02 -1.7091570528E-03 -2.9143678133E-03 + -5.9248857524E-03 9.0562642805E-04 1.0848007387E-02 + 1.2568467539E-03 -4.2400317962E-03 -1.3536213163E-02 + -1.7750302104E-02 1.1175370043E-02 1.4915168889E-03 + 2.0395120880E-02 -3.2871896768E-03 2.1042335941E-03 + 3.7743025755E-04 4.1431908731E-04 1.5499681204E-02 + 2.3694854455E-03 -1.8345281598E-03 -1.5593214989E-02 + -1.8448289016E-02 1.7541848646E-03 5.2663411489E-03 + 1.6994768171E-03 3.8359179890E-03 -1.1996668071E-02 + -1.0573331009E-02 -6.2579594700E-04 7.2754696460E-03 + 1.4082249427E-02 1.4382398008E-03 -3.9005387259E-03 + -2.2164904207E-03 -3.3534242482E-03 1.1437831810E-02 + 9.6688885661E-03 5.4238251462E-03 -1.2876332661E-02 + -2.5610289816E-02 4.3468395897E-03 -2.4457649210E-03 + 1.6861958212E-02 9.3231272756E-04 -8.1151720600E-03 + -2.9292545992E-03 -1.3546107645E-03 1.0173563642E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6159848001E+03 +:LATVEC_SCALE: + 1.5348839051E+01 1.5348839051E+01 1.5348839051E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0827582365E+00 -3.8578756851E-02 5.6571621248E-02 - -3.8578756851E-02 -6.3238712116E-01 -1.5784792332E-01 - 5.6571621248E-02 -1.5784792332E-01 -8.9611599957E-01 + 1.0598445188E+00 1.5628605655E-02 -2.3345214273E-02 + 1.5628605655E-02 7.3148818924E-01 1.6774083417E-01 + -2.3345214273E-02 1.6774083417E-01 8.8802089388E-01 :STRESS: - -1.1707345042E+00 -5.0187434153E-01 1.6605532588E+00 - -5.0187434153E-01 1.5555869976E+00 5.7617894219E-02 - 1.6605532588E+00 5.7617894219E-02 2.0655632288E-01 -:PRESIO: 8.7042045241E-01 -:PRES: -1.9713627212E-01 -:PRESIG: 9.0308896258E-01 + -1.7934641665E+00 -3.6880810653E-01 1.3937607677E+00 + -3.6880810653E-01 1.7330832908E+00 3.6573234108E-02 + 1.3937607677E+00 3.6573234108E-02 -6.2309110699E-01 +:CONSTRESS: + 3.4777606813E+00 7.5365748557E-01 -2.7978081121E+00 + 7.5365748557E-01 -4.3391564281E+00 2.6318249888E-01 + -2.7978081121E+00 2.6318249888E-01 8.6139574678E-01 +:TOTSTRESS: + -6.2445199592E-01 -3.6922077339E-01 1.3807021301E+00 + -3.6922077339E-01 3.3375613265E+00 -1.3201489882E-01 + 1.3807021301E+00 -1.3201489882E-01 6.4971625409E-01 +:PRESIO: 8.9311786731E-01 +:PRES: 2.2782399425E-01 +:CONPRES: 5.6719216493E-14 +:TOTPRES: 1.1209418616E+00 +:PRESIG: 9.2192812110E-01 :MIND: -Al - Al: 4.8790502908E+00 -Si - Si: 4.7099948443E+00 -Al - Si: 4.6386596917E+00 -:MDSTEP: 39 -:MDTM: 1.38 +Al - Al: 4.6735691466E+00 +Si - Si: 4.7533443843E+00 +Al - Si: 4.8116380088E+00 + + +:MDSTEP: 29 +:MDTM: 13.83 :TWIST: 0 :TEL: 1120 -:TIO: 1121.33023281942 -:TEN: -3.2411635607E+00 -:KEN: 5.1601072491E-03 -:KENIG: 5.3265623216E-03 -:FEN: -3.2463236679E+00 -:UEN: -3.2456002029E+00 -:TSEN: -7.2346504566E-04 -:NPT_NP_HAMIL: -2.1263574064E-05 +:TIO: 1117.97684219207 +:TEN: -3.2409615245E+00 +:KEN: 5.1446757064E-03 +:KENIG: 5.3106329873E-03 +:FEN: -3.2461062002E+00 +:UEN: -3.2453160053E+00 +:TSEN: -7.9019491126E-04 +:NPT_NP_HAMIL: -8.0107390832E-05 +:SNOSE[0]: 1.0133210800E+00 +:SNOSE[1]: 4.0989089593E-05 :R: - 3.4449909799E-01 5.0510855194E-01 2.9759275758E-01 - 3.9694054455E+00 1.5454764344E+01 4.2016219978E+00 - 8.1193577519E+00 1.5257758777E+01 4.0186044560E-02 - 1.1439390737E+01 1.5456284451E+01 3.6147673936E+00 - 1.9365256427E-01 8.0394382682E+00 1.5463981424E+01 - 3.7296705777E+00 8.0480825436E+00 3.8333285017E+00 - 7.2463179496E+00 7.4080865058E+00 1.9946101208E-01 - 1.1636840035E+01 7.8798264960E+00 4.1249131248E+00 - 5.6658761544E-01 1.5228385155E+01 7.8101143127E+00 - 3.6417548128E+00 3.6637291387E-02 1.1269495960E+01 - 7.7710069743E+00 6.4459370766E-02 7.8263356167E+00 - 1.1720074382E+01 1.5236503586E+01 1.1925728277E+01 - 3.7428275193E-01 7.7767780909E+00 8.0091751116E+00 - 4.3670489107E+00 8.0021425065E+00 1.1578010303E+01 - 7.2962224373E+00 8.1594227045E+00 7.5546726307E+00 - 1.1634769646E+01 7.2044081088E+00 1.1586939752E+01 - 1.3696364150E-01 3.9887324031E+00 3.9956733752E+00 - 3.7055585271E+00 3.9122303848E+00 3.6311595712E-02 - 7.9668990815E+00 3.5968736256E+00 3.2913761082E+00 - 1.1394704177E+01 3.8555848357E+00 1.5287649188E+01 - 3.8531444390E-01 1.1493530819E+01 3.9759745809E+00 - 3.5784992990E+00 1.1680991683E+01 5.2355542826E-01 - 7.9680478001E+00 1.1850386343E+01 3.8495321126E+00 - 1.0960421355E+01 1.1608855996E+01 1.1438669653E-01 - 1.9087975473E-01 3.7061306758E+00 1.1233392011E+01 - 3.8252343678E+00 3.6860999388E+00 8.1461161692E+00 - 8.0969100910E+00 3.7842984796E+00 1.1637941322E+01 - 1.1414355538E+01 4.0329217877E+00 7.9584501843E+00 - 3.2431056023E-01 1.1639625718E+01 1.1581394204E+01 - 3.6267232482E+00 1.1268395865E+01 7.8000183884E+00 - 8.0120256823E+00 1.1920150000E+01 1.1850110467E+01 - 1.1755336097E+01 1.1639613576E+01 7.9708212525E+00 + 3.6502261136E-01 3.8177766802E-01 2.2129756545E-01 + 3.8955027070E+00 1.5338904186E+01 4.0946715284E+00 + 7.9856262430E+00 1.5187121649E+01 1.1939208595E-01 + 1.1378343087E+01 1.5343097668E+01 3.6363989315E+00 + 1.4540155565E-01 7.9118768116E+00 1.5347935387E+01 + 3.7413401195E+00 7.9075209700E+00 3.8111754074E+00 + 7.2970592869E+00 7.4270061089E+00 1.4637150140E-01 + 1.1539229416E+01 7.7822372317E+00 4.0310744031E+00 + 5.6203347138E-01 1.5172715273E+01 7.7447506809E+00 + 3.6482682970E+00 3.1326824614E-02 1.1241137033E+01 + 7.6987311531E+00 4.7953679457E-02 7.8195602889E+00 + 1.1589399046E+01 1.5177099160E+01 1.1755492998E+01 + 2.8187320145E-01 7.7040225858E+00 7.8778320262E+00 + 4.2181370783E+00 7.8827934661E+00 1.1492989546E+01 + 7.3358418489E+00 7.9998880228E+00 7.5427919562E+00 + 1.1541299185E+01 7.2841020038E+00 1.1498442306E+01 + 8.8386588078E-02 3.9312069440E+00 3.9368359425E+00 + 3.7267454842E+00 3.8697481537E+00 8.1805142015E-03 + 7.8428321932E+00 3.6422206880E+00 3.4335070070E+00 + 1.1386071127E+01 3.8133888542E+00 1.5214702557E+01 + 3.3243277917E-01 1.1436631342E+01 3.9181528190E+00 + 3.6254172278E+00 1.1571679572E+01 4.9408788398E-01 + 7.8407425526E+00 1.1700036117E+01 3.8516482579E+00 + 1.1070424556E+01 1.1515358854E+01 7.1753979349E-02 + 1.3728192570E-01 3.7127482673E+00 1.1258403340E+01 + 3.8225260395E+00 3.7034049601E+00 7.9642861589E+00 + 7.9219887822E+00 3.7734289030E+00 1.1547478867E+01 + 1.1378272762E+01 3.9653709628E+00 7.8265129862E+00 + 3.0141635898E-01 1.1534482515E+01 1.1520238209E+01 + 3.6973287766E+00 1.1261124069E+01 7.8552724824E+00 + 7.8529250427E+00 1.1749283104E+01 1.1714350548E+01 + 1.1635250685E+01 1.1542228092E+01 7.8313250904E+00 :V: - -9.1967321062E-05 4.6272906961E-04 2.8995941108E-04 - 1.9037792976E-04 -3.4932335280E-05 2.7742765985E-04 - 2.2106581436E-04 -1.8764996657E-04 -3.3183812383E-04 - -9.8962596435E-05 -4.7019124668E-05 -1.7683626964E-04 - 1.8132700003E-04 2.3733913540E-04 -3.5050755047E-05 - -1.7262948211E-04 3.0445411303E-04 -3.6614812323E-05 - -4.1139463405E-04 -3.0196175666E-04 1.9951563815E-04 - 2.0331843577E-05 1.4121662260E-04 2.4702233285E-04 - -5.4553977709E-05 -2.6978058570E-04 -1.3549960334E-05 - -1.0628290408E-04 4.6594613995E-06 -2.0083349170E-04 - 4.1811840378E-05 6.9049527842E-05 -2.1275187470E-04 - 1.6792284792E-04 -2.5272405243E-04 2.8673052566E-04 - 3.3750786624E-04 4.2858991795E-05 2.6692603944E-04 - 4.4463292360E-04 2.0921608900E-04 -2.2032582233E-05 - -3.6316233736E-04 3.5765003131E-04 -2.0403338428E-04 - 2.6741039044E-06 -5.4396617362E-04 -1.1376569103E-05 - 2.1617544442E-04 1.0010385542E-04 9.7962197537E-05 - -2.1954219388E-04 4.7467312378E-05 1.3202150702E-04 - 2.4082050773E-04 -3.0781554493E-04 -6.9804364367E-04 - -3.7183652103E-04 6.9906506398E-05 -1.9409850296E-04 - 2.3778231804E-04 -1.4935334066E-04 1.0837900491E-04 - -2.9830433248E-04 6.3651976398E-05 1.3480731395E-04 - 2.5084221930E-04 2.1336052199E-04 -1.6069245073E-04 - -8.1574463873E-04 -5.0804721830E-06 1.7516261009E-04 - 2.0490388731E-04 -1.3677534662E-04 -4.8289304911E-04 - -1.3187121516E-04 -1.8573364271E-04 4.6853962227E-04 - 4.6517117508E-04 -7.8983749516E-05 -1.9661913423E-05 - -2.2800970732E-04 1.2969323200E-04 2.9359258166E-04 - 1.0150939892E-04 6.1029865807E-05 -1.5296287046E-04 - -4.5442719455E-04 -3.1480005560E-04 -4.7374469500E-04 - 4.0567199416E-04 3.0073125331E-04 1.4266351262E-04 - 1.0028874197E-04 8.9684471815E-06 3.1898247275E-04 + -8.9247985557E-05 5.0076173331E-04 3.0001672482E-04 + 1.4121075921E-04 -3.6146378459E-05 3.1807719411E-04 + 3.3613859130E-04 -2.3212269033E-04 -3.0212030635E-04 + -1.5635522862E-04 -4.2250215061E-05 -2.3399286180E-04 + 1.9524027335E-04 2.7479142549E-04 -3.3528761964E-05 + -1.5887209672E-04 3.1135036482E-04 -3.5315493995E-05 + -4.7640879839E-04 -3.3359067534E-04 2.1105244204E-04 + 1.3807724897E-05 1.3467404229E-04 2.4954711682E-04 + 7.4769068420E-05 -2.6876115257E-04 3.9058178419E-05 + -1.8989375228E-04 3.4311802028E-05 -3.1107986595E-04 + 3.0303064457E-05 6.4139613720E-05 -2.3590277725E-04 + 1.2183997520E-04 -2.5923785484E-04 3.1336840348E-04 + 3.8044627580E-04 4.0176397323E-05 2.7009236345E-04 + 4.7897232603E-04 2.3964398380E-04 -4.4687273284E-05 + -4.3713128989E-04 4.0206245309E-04 -1.9342786575E-04 + 3.4942508524E-06 -5.6462991997E-04 -2.6187535444E-05 + 1.6544117335E-04 1.0632555210E-04 1.2074562289E-04 + -1.8732705415E-04 4.1005875581E-05 8.5450091386E-05 + 2.3979731689E-04 -2.9061259099E-04 -6.5469914844E-04 + -2.9301265644E-04 1.7733717513E-05 -2.1152877003E-04 + 1.6329516754E-04 -1.4060260365E-04 9.9479144612E-05 + -3.1215981665E-04 5.6769918638E-05 7.2100693470E-05 + 2.5429436885E-04 2.2965634610E-04 -1.0228086752E-04 + -7.7122804246E-04 7.3659914359E-06 1.5401482028E-04 + 2.0863139121E-04 -1.5862798844E-04 -4.4128199981E-04 + -9.1191397119E-05 -1.9564298145E-04 4.5774340678E-04 + 4.1249130980E-04 -8.1088720006E-05 -2.1062683400E-06 + -2.1894605970E-04 1.5669252725E-04 2.4722823006E-04 + 6.1239048418E-05 3.1517654995E-05 -1.0349220259E-04 + -3.4911247792E-04 -3.6062722284E-04 -4.6996561058E-04 + 3.5043426203E-04 3.0723001315E-04 1.8916209559E-04 + 1.0958234994E-04 1.8150243146E-05 2.8565755844E-04 :F: - 2.2826679200E-04 -5.8515706555E-03 -1.6487757382E-03 - 1.0028699641E-02 -4.2445089113E-04 -7.4008687988E-03 - -2.6293585918E-02 1.1621230047E-02 -6.5428593312E-03 - 1.1687037369E-02 -9.6945968345E-04 1.1991958920E-02 - -1.9904696885E-03 -6.2949557198E-03 -8.6117986503E-04 - -2.6108763797E-03 -9.4613545338E-04 -1.6194771278E-03 - 1.1269703055E-02 5.1360182632E-03 -3.2849129002E-03 - 2.4346697463E-03 2.3334577962E-03 2.4788882003E-03 - -2.6203263147E-02 -1.9189896235E-03 -1.1024342737E-02 - 1.7301761782E-02 -7.8098526596E-03 2.3741801382E-02 - 2.3482121394E-03 2.4998654252E-03 5.2437743713E-03 - 1.1821594675E-02 -1.1224750263E-05 -5.5676936555E-03 - -1.0389851555E-02 -6.5033668918E-04 1.1449735478E-04 - -4.2748739378E-03 -4.4169957648E-03 5.7831208840E-03 - 1.4786503508E-02 -8.2554532290E-03 -4.6730856455E-03 - 1.8941791485E-03 4.0370779383E-03 3.4834854811E-03 - 1.2966329896E-02 -3.1968296313E-04 -5.1913304996E-03 - -8.7665946001E-03 2.0630270347E-03 9.5901427656E-03 - 1.5597194334E-03 -5.6074437828E-03 -1.1258822728E-02 - -1.9019151800E-02 1.1236578881E-02 3.9720939440E-03 - 1.4961727692E-02 -2.3849968306E-03 2.1267775146E-03 - 2.2409396546E-03 2.1574451810E-03 1.4352511074E-02 - -1.5451825976E-03 -3.1891724042E-03 -1.1484265632E-02 - -7.9112405276E-03 -5.4539167024E-03 4.5730917097E-03 - -2.0818593807E-03 4.0333548412E-03 -9.6654028520E-03 - -8.5923871533E-03 2.4091643611E-03 4.8702687096E-04 - 1.1799276977E-02 -1.5109077189E-03 -3.2859171177E-03 - -3.0841438315E-03 -6.1466266630E-03 9.5855641869E-03 - 9.3703063423E-03 7.3017854168E-03 -1.0707169166E-02 - -2.4172479925E-02 1.0744223722E-02 -8.8648889056E-04 - 1.0212956539E-02 -4.3685772488E-04 -9.7649158445E-03 - 2.4076049629E-05 -2.9741989979E-03 7.3427738707E-03 -:LATVEC_SCALE: 1.5494735713E+01 1.5494735713E+01 1.5494735713E+01 + -1.1195195279E-03 -5.4496115005E-03 -1.3962363196E-03 + 1.0806931088E-02 1.5092943553E-05 -6.0683754802E-03 + -1.7959553642E-02 5.2260409017E-03 -6.6053825068E-03 + 9.5854126086E-03 -1.3131798432E-03 9.5714349409E-03 + -1.8279250116E-03 -6.2263311430E-03 -3.8265841297E-04 + -3.5469740504E-03 1.4189031164E-03 3.2440644923E-04 + 1.0448341013E-02 4.5745461718E-03 -6.3070389689E-04 + 8.1696592551E-04 1.4639332575E-03 -1.5204957574E-04 + -2.3389217272E-02 -5.9745943891E-04 -9.3433320926E-03 + 1.4589959163E-02 -4.2285272378E-03 1.7859425883E-02 + 1.4093990128E-03 9.3883455430E-04 3.1311464265E-03 + 7.7719100727E-03 3.9547949090E-05 -2.5995437765E-03 + -4.8371354898E-03 2.2223390674E-03 3.3643751943E-04 + -5.5720576104E-03 -5.2386589639E-03 2.8376061734E-03 + 1.0607665001E-02 -6.4717733972E-03 -1.9925129463E-03 + -7.6283450530E-04 -1.8627892406E-04 2.6495604788E-03 + 1.0620287837E-02 -1.5482166221E-03 -3.1202656732E-03 + -6.1838004162E-03 1.0083099941E-03 1.0746962721E-02 + 1.1809134185E-03 -4.4728753711E-03 -1.3397224808E-02 + -1.8017124056E-02 1.1300745331E-02 1.5949413571E-03 + 2.0215576829E-02 -3.3540123043E-03 2.2058948087E-03 + 5.3228352296E-04 5.3124012355E-04 1.5531201358E-02 + 1.9840858311E-03 -1.9314541604E-03 -1.5337119675E-02 + -1.7725091765E-02 1.3129364332E-03 5.1053353089E-03 + 1.4286340551E-03 3.8771405154E-03 -1.1925326208E-02 + -1.0502726183E-02 -5.1751432444E-04 6.7008911786E-03 + 1.4070381092E-02 1.2160435645E-03 -3.8178706834E-03 + -2.3135565835E-03 -3.5347321618E-03 1.1512856199E-02 + 9.6002547899E-03 5.6785519572E-03 -1.2706674128E-02 + -2.5757066638E-02 4.7996980255E-03 -2.4996725523E-03 + 1.6449594551E-02 9.5952586479E-04 -8.0465995949E-03 + -2.6040130600E-03 -1.5128043786E-03 9.9134475273E-03 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6310456236E+03 +:LATVEC_SCALE: + 1.5370119188E+01 1.5370119188E+01 1.5370119188E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0832223028E+00 -4.0333039104E-02 5.8288383766E-02 - -4.0333039104E-02 -6.2071633964E-01 -1.5565225930E-01 - 5.8288383766E-02 -1.5565225930E-01 -8.9397488881E-01 + 1.0602425707E+00 1.8145508870E-02 -2.7412972830E-02 + 1.8145508870E-02 7.2049336032E-01 1.6658486985E-01 + -2.7412972830E-02 1.6658486985E-01 8.8712958917E-01 :STRESS: - -1.0313085891E+00 -5.1797432759E-01 1.6656384166E+00 - -5.1797432759E-01 1.6002328123E+00 6.0956560337E-02 - 1.6656384166E+00 6.0956560337E-02 3.1634838851E-01 -:PRESIO: 8.6597117709E-01 -:PRES: -2.9509087057E-01 -:PRESIG: 8.9869199742E-01 + -1.5730896609E+00 -3.7928167143E-01 1.4125396713E+00 + -3.7928167143E-01 1.8154231491E+00 3.6747779529E-02 + 1.4125396713E+00 3.6747779529E-02 -3.4884775650E-01 +:CONSTRESS: + 3.4280609227E+00 7.7888358303E-01 -2.8460049899E+00 + 7.7888358303E-01 -4.1263403398E+00 2.6091132255E-01 + -2.8460049899E+00 2.6091132255E-01 6.9827941709E-01 +:TOTSTRESS: + -7.9472869106E-01 -3.8145640273E-01 1.4060523458E+00 + -3.8145640273E-01 3.0314105510E+00 -1.3107423223E-01 + 1.4060523458E+00 -1.3107423223E-01 5.3769792859E-01 +:PRESIO: 8.8928850673E-01 +:PRES: 3.5504756102E-02 +:CONPRES: 8.9979870101E-14 +:TOTPRES: 9.2479326284E-01 +:PRESIG: 9.1797523276E-01 :MIND: -Al - Al: 4.8825877655E+00 -Si - Si: 4.7064603579E+00 -Al - Si: 4.6251096889E+00 -:MDSTEP: 40 -:MDTM: 1.36 +Al - Al: 4.6692484055E+00 +Si - Si: 4.7524946379E+00 +Al - Si: 4.7958411194E+00 + + +:MDSTEP: 30 +:MDTM: 13.88 :TWIST: 0 :TEL: 1120 -:TIO: 1119.76317117577 -:TEN: -3.2411855969E+00 -:KEN: 5.1528959870E-03 -:KENIG: 5.3191184382E-03 -:FEN: -3.2463384929E+00 -:UEN: -3.2456130177E+00 -:TSEN: -7.2547527780E-04 -:NPT_NP_HAMIL: -2.0023298614E-05 +:TIO: 1118.51426783807 +:TEN: -3.2409825565E+00 +:KEN: 5.1471488173E-03 +:KENIG: 5.3131858759E-03 +:FEN: -3.2461297053E+00 +:UEN: -3.2453512347E+00 +:TSEN: -7.7847058532E-04 +:NPT_NP_HAMIL: -6.7041728984E-05 +:SNOSE[0]: 1.0141088356E+00 +:SNOSE[1]: 3.2668225077E-05 :R: - 3.4264406488E-01 5.1711782970E-01 3.0512021818E-01 - 3.9790970191E+00 1.5472773466E+01 4.2135363430E+00 - 8.1344255141E+00 1.5271893768E+01 3.1931204972E-02 - 1.1451059392E+01 1.5473989137E+01 3.6149515552E+00 - 1.9835712177E-01 8.0550615155E+00 1.5481993415E+01 - 3.7299168661E+00 8.0654461418E+00 3.8370839355E+00 - 7.2451176808E+00 7.4097187024E+00 2.0460716194E-01 - 1.1651590120E+01 7.8929808864E+00 4.1361038445E+00 - 5.6560061960E-01 1.5240280060E+01 7.8191818682E+00 - 3.6437864415E+00 3.6699907459E-02 1.1278583580E+01 - 7.7815655941E+00 6.6280240153E-02 7.8306905168E+00 - 1.1738700406E+01 1.5248854869E+01 1.1947332015E+01 - 3.8297281053E-01 7.7873322371E+00 8.0255745751E+00 - 4.3833473638E+00 8.0170468358E+00 1.1591680671E+01 - 7.2963221625E+00 8.1781490524E+00 7.5587877629E+00 - 1.1649072929E+01 7.1997814505E+00 1.1600856323E+01 - 1.4264294274E-01 3.9960816506E+00 4.0029195525E+00 - 3.7045403548E+00 3.9182105692E+00 3.9742268757E-02 - 7.9826173591E+00 3.5935733992E+00 3.2779658931E+00 - 1.1399182698E+01 3.8621619396E+00 1.5301563381E+01 - 3.9185645988E-01 1.1503842375E+01 3.9835426516E+00 - 3.5755065115E+00 1.1696864553E+01 5.2770752982E-01 - 7.9839785213E+00 1.1870111392E+01 3.8501153558E+00 - 1.0953503689E+01 1.1622846339E+01 1.1892145426E-01 - 1.9616498513E-01 3.7073176347E+00 1.1235034039E+01 - 3.8265367680E+00 3.6860298571E+00 8.1676828528E+00 - 8.1184690044E+00 3.7869463122E+00 1.1651631930E+01 - 1.1422613058E+01 4.0409882212E+00 7.9755620593E+00 - 3.2733440296E-01 1.1655444841E+01 1.1591623754E+01 - 3.6196039200E+00 1.1274490624E+01 7.7977981786E+00 - 8.0319876042E+00 1.1942158158E+01 1.1868004530E+01 - 1.1772181950E+01 1.1654019361E+01 7.9885504178E+00 + 3.6330902134E-01 3.9471017016E-01 2.2904702168E-01 + 3.9045132002E+00 1.5359413874E+01 4.1082458820E+00 + 8.0050048536E+00 1.5202586083E+01 1.1201576835E-01 + 1.1390400544E+01 1.5363453335E+01 3.6357238530E+00 + 1.5044081020E-01 7.9297027225E+00 1.5368520184E+01 + 3.7425945949E+00 7.9262964207E+00 3.8156194698E+00 + 7.2954794087E+00 7.4291169536E+00 1.5181221846E-01 + 1.1555681617E+01 7.7964512806E+00 4.0428954553E+00 + 5.6452790765E-01 1.5187213414E+01 7.7564706253E+00 + 3.6487361770E+00 3.2196024229E-02 1.1249213027E+01 + 7.7102368088E+00 4.9619055578E-02 7.8246355186E+00 + 1.1608647229E+01 1.5191843869E+01 1.1779663657E+01 + 2.9168270283E-01 7.7157858691E+00 7.8955348376E+00 + 4.2358818420E+00 7.8997122684E+00 1.1507937447E+01 + 7.3352923460E+00 8.0209953396E+00 7.5485034891E+00 + 1.1557488302E+01 7.2802469453E+00 1.1513855984E+01 + 9.2681693790E-02 3.9393240976E+00 3.9453095433E+00 + 3.7272580723E+00 3.8761730386E+00 1.0378283518E-02 + 7.8597389356E+00 3.6400610453E+00 3.4219622065E+00 + 1.1394577803E+01 3.8192191509E+00 1.5230693698E+01 + 3.3707290974E-01 1.1449081090E+01 3.9261043407E+00 + 3.6227292276E+00 1.1589241884E+01 4.9666110461E-01 + 7.8580111687E+00 1.1722055486E+01 3.8543917822E+00 + 1.1066618479E+01 1.1531620577E+01 7.5708985324E-02 + 1.4266238541E-01 3.7140144305E+00 1.1263086987E+01 + 3.8255333493E+00 3.7037125746E+00 7.9868071634E+00 + 7.9433714843E+00 3.7766890298E+00 1.1563519361E+01 + 1.1388702071E+01 3.9747744484E+00 7.8436436094E+00 + 3.0341531784E-01 1.1551396867E+01 1.1533669826E+01 + 3.6936654760E+00 1.1267914757E+01 7.8545511799E+00 + 7.8726848064E+00 1.1773314730E+01 1.1735347646E+01 + 1.1654194180E+01 1.1558778087E+01 7.8494070011E+00 :V: - -9.1651034316E-05 4.5877101985E-04 2.8849467265E-04 - 1.9500761470E-04 -3.5069421440E-05 2.7309580406E-04 - 2.0735022052E-04 -1.8139096726E-04 -3.3440385389E-04 - -9.2864716703E-05 -4.7403998282E-05 -1.7041439566E-04 - 1.7992823157E-04 2.3365159450E-04 -3.5407352229E-05 - -1.7356524753E-04 3.0331121165E-04 -3.7349573737E-05 - -4.0482250446E-04 -2.9871588462E-04 1.9742564599E-04 - 2.1512487000E-05 1.4208158330E-04 2.4772875079E-04 - -6.7620481804E-05 -2.7015540890E-04 -1.9067944599E-05 - -9.7343555330E-05 7.1918940374E-07 -1.8844631566E-04 - 4.2901933128E-05 7.0156281901E-05 -2.0964715716E-04 - 1.7350393104E-04 -2.5217620753E-04 2.8330078437E-04 - 3.3154031490E-04 4.2437864035E-05 2.6639905937E-04 - 4.4150793034E-04 2.0653516603E-04 -1.9074151397E-05 - -3.5492612054E-04 3.5271243648E-04 -2.0593811487E-04 - 3.6214345072E-06 -5.4074329314E-04 -9.5986966331E-06 - 2.2197053777E-04 9.9730067024E-05 9.5237913209E-05 - -2.2329956165E-04 4.8360719259E-05 1.3636869710E-04 - 2.4104712702E-04 -3.0985230043E-04 -7.0195790249E-04 - -3.8021692186E-04 7.5185700764E-05 -1.9175310658E-04 - 2.4449476027E-04 -1.5017926149E-04 1.0916982851E-04 - -2.9656763631E-04 6.4555583315E-05 1.4145075842E-04 - 2.4954583246E-04 2.1135144123E-04 -1.6589255748E-04 - -8.1778273881E-04 -7.7060284276E-06 1.7698983504E-04 - 2.0344865535E-04 -1.3452587780E-04 -4.8650817630E-04 - -1.3573637182E-04 -1.8416216088E-04 4.6774892104E-04 - 4.6985673149E-04 -7.9541211172E-05 -2.1207420477E-05 - -2.2900136302E-04 1.2643761757E-04 2.9758369985E-04 - 1.0581713447E-04 6.4426234466E-05 -1.5780422041E-04 - -4.6511807694E-04 -3.0891633956E-04 -4.7313571306E-04 - 4.0972095747E-04 2.9986142103E-04 1.3763023857E-04 - 1.0008073813E-04 7.5109358778E-06 3.2183371265E-04 + -8.9561599621E-05 4.9691764968E-04 2.9865535417E-04 + 1.4634466120E-04 -3.6084378400E-05 3.1430595390E-04 + 3.2618413324E-04 -2.2887683845E-04 -3.0479570907E-04 + -1.5113380717E-04 -4.2818788310E-05 -2.2860461358E-04 + 1.9389340306E-04 2.7106603418E-04 -3.3652884278E-05 + -1.6031437736E-04 3.1138573238E-04 -3.5126834839E-05 + -4.7010781294E-04 -3.3055345272E-04 2.1021333265E-04 + 1.4229556429E-05 1.3514694904E-04 2.4900052401E-04 + 6.2755073798E-05 -2.6852509745E-04 3.4212785377E-05 + -1.8206236641E-04 3.2022523693E-05 -3.0126746179E-04 + 3.0946470452E-05 6.4525598648E-05 -2.3375131258E-04 + 1.2557334003E-04 -2.5868111184E-04 3.1131091979E-04 + 3.7707066333E-04 4.1180991613E-05 2.6966762395E-04 + 4.7517069768E-04 2.3650316415E-04 -4.3082385812E-05 + -4.3074596478E-04 3.9788815727E-04 -1.9408339806E-04 + 3.1644201527E-06 -5.6344212394E-04 -2.4786376721E-05 + 1.7029865471E-04 1.0538410087E-04 1.1892349906E-04 + -1.8997749923E-04 4.1429609657E-05 9.0439002264E-05 + 2.3984018552E-04 -2.9220022285E-04 -6.5972989963E-04 + -3.0115786105E-04 2.3188480586E-05 -2.1026840380E-04 + 1.7267142489E-04 -1.4193318735E-04 1.0035085316E-04 + -3.1119048392E-04 5.6932013674E-05 7.9465359270E-05 + 2.5461385368E-04 2.2819942878E-04 -1.0941723471E-04 + -7.7795163671E-04 7.8738381328E-06 1.5611775307E-04 + 2.0880492066E-04 -1.5639897863E-04 -4.4607406413E-04 + -9.6057272255E-05 -1.9543828019E-04 4.5985386012E-04 + 4.1839669625E-04 -8.0381711967E-05 -3.9286120872E-06 + -2.1961512542E-04 1.5459930118E-04 2.5226848086E-04 + 6.5739872688E-05 3.4256292837E-05 -1.0937674010E-04 + -3.6084797191E-04 -3.5741277444E-04 -4.7015840914E-04 + 3.5752697383E-04 3.0703046112E-04 1.8486896056E-04 + 1.0816235608E-04 1.7339901328E-05 2.8977408478E-04 :F: - 3.2227406406E-04 -5.7092995543E-03 -1.6743068895E-03 - 9.8400678890E-03 -4.8125024341E-04 -7.4541858786E-03 - -2.6955891116E-02 1.2318178600E-02 -6.4153264970E-03 - 1.1671173366E-02 -9.1932888410E-04 1.2094996369E-02 - -1.8937428066E-03 -6.2170026282E-03 -9.4214405237E-04 - -2.4116856329E-03 -1.2569517383E-03 -1.8380568562E-03 - 1.1216397190E-02 5.0411974245E-03 -3.5298036971E-03 - 2.6080860675E-03 2.4247859774E-03 2.8183351095E-03 - -2.6135943331E-02 -2.0230235350E-03 -1.0988839542E-02 - 1.7352880886E-02 -8.0732404294E-03 2.4062723883E-02 - 2.4733336264E-03 2.6649837440E-03 5.3995693786E-03 - 1.2201228445E-02 -2.8943701688E-05 -5.7768263138E-03 - -1.0930655649E-02 -1.0762587971E-03 1.3647180729E-04 - -4.1243572662E-03 -4.2133098901E-03 5.9480402611E-03 - 1.4949302580E-02 -8.2772005088E-03 -4.9709378267E-03 - 2.2444019780E-03 4.4407459013E-03 3.5867668522E-03 - 1.3180658943E-02 -2.3076304241E-04 -5.3411943071E-03 - -9.0242379830E-03 2.1538225441E-03 9.4688617824E-03 - 1.7714941729E-03 -5.6504449910E-03 -1.1187728240E-02 - -1.9055932349E-02 1.1086158168E-02 4.2637285827E-03 - 1.4321179579E-02 -2.2175203066E-03 2.0145759086E-03 - 2.2965508448E-03 2.3038207338E-03 1.4300740895E-02 - -1.7981205980E-03 -3.2769947887E-03 -1.1067640234E-02 - -6.9965899687E-03 -6.0972175353E-03 4.5844952309E-03 - -2.4306650855E-03 3.9842462578E-03 -9.4537357532E-03 - -8.4387398559E-03 2.7517548692E-03 -9.2802546544E-05 - 1.1500195762E-02 -1.8492998530E-03 -3.2319857695E-03 - -3.1736358491E-03 -6.3923084637E-03 9.2164929837E-03 - 9.4573455299E-03 7.3435671839E-03 -1.0630753066E-02 - -2.3844479801E-02 1.1199802346E-02 -4.9954911495E-04 - 9.5273925255E-03 -5.9570706092E-04 -9.9946636469E-03 - 2.8071384341E-04 -3.1269977990E-03 7.1946811865E-03 -:LATVEC_SCALE: 1.5513664511E+01 1.5513664511E+01 1.5513664511E+01 + -8.9442115937E-04 -5.4986118333E-03 -1.4245126268E-03 + 1.0790917863E-02 -8.0157467942E-05 -6.1639701206E-03 + -1.8664036354E-02 5.6604172721E-03 -6.6179861029E-03 + 9.7968693148E-03 -1.3079473687E-03 9.8044775448E-03 + -1.8376597770E-03 -6.1969261432E-03 -3.9885618948E-04 + -3.5471780288E-03 1.4030145306E-03 1.2064114305E-04 + 1.0463591000E-02 4.6101956253E-03 -8.8261869830E-04 + 9.7645617316E-04 1.5732682600E-03 1.3097449406E-04 + -2.3662262266E-02 -7.7989353693E-04 -9.5563257918E-03 + 1.4864998819E-02 -4.5640655555E-03 1.8416185743E-02 + 1.4059190247E-03 1.1457056768E-03 3.3782272795E-03 + 8.0985852841E-03 -6.1834753789E-05 -2.8695301382E-03 + -5.2870270646E-03 2.1120509944E-03 3.0353472614E-04 + -5.3955228589E-03 -5.1665930069E-03 3.1486139991E-03 + 1.0976987863E-02 -6.6373132846E-03 -2.2755404794E-03 + -5.1677095194E-04 3.8751587416E-05 2.6874784882E-03 + 1.0935430196E-02 -1.3892112035E-03 -3.3267632007E-03 + -6.4478718334E-03 1.1102118028E-03 1.0635240684E-02 + 1.1459792469E-03 -4.6928236777E-03 -1.3261038849E-02 + -1.8268405205E-02 1.1399250264E-02 1.7169447508E-03 + 1.9994761064E-02 -3.4048599524E-03 2.2880408194E-03 + 6.7479597702E-04 6.4739517051E-04 1.5548698487E-02 + 1.6162115540E-03 -2.0301721256E-03 -1.5070229082E-02 + -1.6973945571E-02 8.5221048322E-04 4.9656160042E-03 + 1.1590603748E-03 3.9118770722E-03 -1.1833330119E-02 + -1.0422482193E-02 -3.9059726019E-04 6.1244407113E-03 + 1.4030783410E-02 9.7890197259E-04 -3.7317122819E-03 + -2.4139454161E-03 -3.7103739246E-03 1.1531650008E-02 + 9.5478831920E-03 5.9208086062E-03 -1.2538397330E-02 + -2.5867953271E-02 5.2502118372E-03 -2.5101218442E-03 + 1.6002164783E-02 9.7005671932E-04 -7.9985185955E-03 + -2.2819131891E-03 -1.6729467798E-03 9.6586865672E-03 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6462694016E+03 +:LATVEC_SCALE: + 1.5391569853E+01 1.5391569853E+01 1.5391569853E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0848689885E+00 -4.1963928121E-02 5.9879151436E-02 - -4.1963928121E-02 -6.0974202060E-01 -1.5347261018E-01 - 5.9879151436E-02 -1.5347261018E-01 -8.9265709315E-01 + 1.0613937669E+00 2.0629714392E-02 -3.1229904541E-02 + 2.0629714392E-02 7.0993129111E-01 1.6546998129E-01 + -3.1229904541E-02 1.6546998129E-01 8.8667880452E-01 :STRESS: - -8.9649559003E-01 -5.3415135859E-01 1.6687139585E+00 - -5.3415135859E-01 1.6425263303E+00 6.4351991651E-02 - 1.6687139585E+00 6.4351991651E-02 4.0943180285E-01 -:PRESIO: 8.6242270075E-01 -:PRES: -3.8515418103E-01 -:PRESIG: 8.9415509461E-01 + -1.3597652886E+00 -3.9050512140E-01 1.4289199314E+00 + -3.9050512140E-01 1.9010381196E+00 3.7349401790E-02 + 1.4289199314E+00 3.7349401790E-02 -8.6687852853E-02 +:CONSTRESS: + 3.3829702213E+00 8.0558435243E-01 -2.8892048624E+00 + 8.0558435243E-01 -3.9306862223E+00 2.5790931573E-01 + -2.8892048624E+00 2.5790931573E-01 5.4771600098E-01 +:TOTSTRESS: + -9.6181116578E-01 -3.9444951664E-01 1.4290550265E+00 + -3.9444951664E-01 2.7395793938E+00 -1.2978873623E-01 + 1.4290550265E+00 -1.2978873623E-01 4.2565065640E-01 +:PRESIO: 8.8600128751E-01 +:PRES: -1.5152832605E-01 +:CONPRES: 1.2360602540E-13 +:TOTPRES: 7.3447296146E-01 +:PRESIG: 9.1458197420E-01 :MIND: -Al - Al: 4.8866079902E+00 -Si - Si: 4.7027312916E+00 -Al - Si: 4.6119753036E+00 +Al - Al: 4.6655704047E+00 +Si - Si: 4.7514485578E+00 +Al - Si: 4.7802493575E+00 diff --git a/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.refout b/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.refout index 82534768..10f726d1 100644 --- a/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.refout +++ b/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.refout @@ -1,8 +1,8 @@ *************************************************************************** -* SPARC (version June 24, 2024) * +* SPARC (version December 03, 2025) * * Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * * Distributed under GNU General Public License 3 (GPL) * -* Start time: Mon Jun 24 20:02:38 2024 * +* Start time: Mon Apr 6 12:43:05 2026 * *************************************************************************** Input parameters *************************************************************************** @@ -11,7 +11,7 @@ LATVEC: 1.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 -FD_GRID: 50 50 50 +FD_GRID: 75 75 75 FD_ORDER: 12 BC: P P P KPOINT_GRID: 1 1 1 @@ -20,8 +20,9 @@ SPIN_TYP: 0 ELEC_TEMP_TYPE: Fermi-Dirac ELEC_TEMP: 1120 EXCHANGE_CORRELATION: GGA_PBE +HUBBARD_FLAG: 0 NSTATES: 76 -CHEB_DEGREE: 25 +CHEB_DEGREE: 35 CHEFSI_BOUND_FLAG: 0 CALC_STRESS: 1 TWTIME: 1E+09 @@ -34,9 +35,10 @@ ION_VEL_DSTR_RAND: 0 ION_TEMP: 1120 NPT_SCALE_VECS: 1 2 3 NPT_SCALE_CONSTRAINTS: 123 +NPT_NP_ANGLES: 0 NPT_NP_QMASS: 500 NPT_NP_BMASS: 0.1 -TARGET_PRESSURE: 0 GPa +TARGET_STRESS: 0 0 0 0 0 0 GPa RESTART_FLAG: 1 MAXIT_SCF: 100 MINIT_SCF: 2 @@ -48,7 +50,7 @@ TOL_LANCZOS: 1.00E-02 TOL_PSEUDOCHARGE: 5.00E-10 MIXING_VARIABLE: density MIXING_PRECOND: kerker -TOL_PRECOND: 9.00E-05 +TOL_PRECOND: 4.00E-05 PRECOND_KERKER_KTF: 1 PRECOND_KERKER_THRESH: 0 MIXING_PARAMETER: 1 @@ -69,7 +71,7 @@ PRINT_VELS: 1 PRINT_RESTART: 1 PRINT_RESTART_FQ: 1 PRINT_ENERGY_DENSITY: 0 -OUTPUT_FILE: Al16Si16_NPTNP_restart/temp_run/Al16Si16_NPTNP_restart +OUTPUT_FILE: Al16Si16_NPTNP_restart *************************************************************************** Cell *************************************************************************** @@ -84,491 +86,511 @@ Density: 2.6105618252E-01 (amu/Bohr^3), 2.9253624436E+00 (g/cc) *************************************************************************** NP_SPIN_PARAL: 1 NP_KPOINT_PARAL: 1 -NP_BAND_PARAL: 19 +NP_BAND_PARAL: 7 NP_DOMAIN_PARAL: 5 1 1 -NP_DOMAIN_PHI_PARAL: 4 4 6 +NP_DOMAIN_PHI_PARAL: 3 3 4 EIG_SERIAL_MAXNS: 1500 *************************************************************************** Initialization *************************************************************************** -Number of processors : 96 -Mesh spacing : 0.3 (Bohr) +Number of processors : 36 +Mesh spacing : 0.2 (Bohr) Number of symmetry adapted k-points: 1 -Output printed to : Al16Si16_NPTNP_restart/temp_run/Al16Si16_NPTNP_restart.out -MD output printed to : Al16Si16_NPTNP_restart/temp_run/Al16Si16_NPTNP_restart.aimd +Output printed to : Al16Si16_NPTNP_restart.out +MD output printed to : Al16Si16_NPTNP_restart.aimd Total number of atom types : 2 Total number of atoms : 32 Total number of electrons : 112 Atom type 1 (valence electrons) : Al 3 -Pseudopotential : ../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +Pseudopotential : ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 Atomic mass : 26.9815385 -Pseudocharge radii of atom type 1 : 7.80 7.80 7.80 (x, y, z dir) +Pseudocharge radii of atom type 1 : 7.20 7.20 7.20 (x, y, z dir) Number of atoms of type 1 : 16 Atom type 2 (valence electrons) : Si 4 -Pseudopotential : ../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 +Pseudopotential : ../../../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 Atomic mass : 28.085 -Pseudocharge radii of atom type 2 : 7.80 7.80 7.80 (x, y, z dir) +Pseudocharge radii of atom type 2 : 7.20 7.20 7.20 (x, y, z dir) Number of atoms of type 2 : 16 -Estimated total memory usage : 548.33 MB -Estimated memory per processor : 5.71 MB -WARNING: Atoms are too close to boundary for b calculation. +Estimated total memory usage : 1.81 GB +Estimated memory per processor : 51.36 MB *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.3240291435853 15.3240291435853 15.3240291435853 -CHEB_DEGREE: 25 +LATVEC_SCALE: 15.208636471 15.208636471 15.208636471 +CHEB_DEGREE: 35 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.306481 (Bohr) +Mesh spacing : 0.202782 (Bohr) =================================================================== - Self Consistent Field (SCF#30) + Self Consistent Field (SCF#20) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2329884583E+00 1.303E-01 0.602 -2 -3.2420456033E+00 4.122E-02 0.139 -3 -3.2448528248E+00 2.104E-02 0.140 -4 -3.2456714996E+00 1.082E-02 0.141 -5 -3.2459560392E+00 4.893E-03 0.138 -6 -3.2460620616E+00 3.271E-03 0.139 -7 -3.2460991264E+00 1.637E-03 0.136 -8 -3.2461119762E+00 5.210E-04 0.135 -9 -3.2461164649E+00 5.307E-04 0.141 -10 -3.2461178716E+00 1.518E-04 0.132 -11 -3.2461183330E+00 5.676E-05 0.131 -12 -3.2461184828E+00 8.971E-05 0.135 -13 -3.2461185286E+00 2.170E-05 0.134 -14 -3.2461185436E+00 2.081E-05 0.174 -15 -3.2461185491E+00 5.810E-06 0.141 -16 -3.2461185510E+00 9.885E-06 0.132 -17 -3.2461185511E+00 2.463E-06 0.134 -18 -3.2461185514E+00 8.270E-07 0.147 -19 -3.2461185516E+00 2.430E-06 0.129 -20 -3.2461185516E+00 2.941E-07 0.136 -Total number of SCF: 20 +1 -3.2260280535E+00 1.274E-01 5.498 +2 -3.2401516764E+00 4.206E-02 1.498 +3 -3.2437113717E+00 2.259E-02 1.445 +4 -3.2449771722E+00 1.594E-02 1.471 +5 -3.2454941393E+00 9.652E-03 1.436 +6 -3.2457002971E+00 5.290E-03 1.468 +7 -3.2457789084E+00 2.515E-03 1.463 +8 -3.2458101921E+00 1.195E-03 1.450 +9 -3.2458224379E+00 5.556E-04 1.428 +10 -3.2458271961E+00 3.707E-04 1.413 +11 -3.2458289960E+00 1.951E-04 1.412 +12 -3.2458296635E+00 1.067E-04 1.406 +13 -3.2458299146E+00 1.481E-04 1.405 +14 -3.2458300019E+00 3.672E-05 1.396 +15 -3.2458300337E+00 1.940E-05 1.401 +16 -3.2458300456E+00 3.739E-05 1.394 +17 -3.2458300494E+00 8.839E-06 1.370 +18 -3.2458300511E+00 1.123E-05 1.389 +19 -3.2458300516E+00 9.107E-07 1.378 +20 -3.2458300520E+00 1.595E-06 1.386 +21 -3.2458300520E+00 2.002E-06 1.369 +22 -3.2458300520E+00 3.205E-06 1.360 +23 -3.2458300521E+00 2.171E-06 1.356 +24 -3.2458300520E+00 2.279E-06 1.351 +25 -3.2458300521E+00 2.232E-06 1.338 +26 -3.2458300521E+00 1.897E-06 1.358 +27 -3.2458300521E+00 6.407E-07 1.335 +28 -3.2458300520E+00 4.583E-07 1.345 +Total number of SCF: 28 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2461185516E+00 (Ha/atom) -Total free energy : -1.0387579365E+02 (Ha) -Band structure energy : 4.4429156743E+00 (Ha) -Exchange correlation energy : -4.1745492641E+01 (Ha) -Self and correction energy : -1.6501175676E+02 (Ha) --Entropy*kb*T : -2.4745101330E-02 (Ha) -Fermi level : 1.9816330908E-01 (Ha) -RMS force : 1.3263430648E-02 (Ha/Bohr) -Maximum force : 2.6870513145E-02 (Ha/Bohr) -Time for force calculation : 0.054 (sec) -Pressure : 8.4126053965E-01 (GPa) -Maximum stress : 2.4739868637E+00 (GPa) -Time for stress calculation : 0.098 (sec) -MD step time : 3.514 (sec) +Free energy per atom : -3.2458300520E+00 (Ha/atom) +Total free energy : -1.0386656166E+02 (Ha) +Band structure energy : 5.1414270545E+00 (Ha) +Exchange correlation energy : -4.1881294939E+01 (Ha) +Self and correction energy : -1.6501201618E+02 (Ha) +-Entropy*kb*T : -2.9756567977E-02 (Ha) +Fermi level : 2.0509967938E-01 (Ha) +RMS force : 1.2175540320E-02 (Ha/Bohr) +Maximum force : 2.3705088748E-02 (Ha/Bohr) +Time for force calculation : 0.128 (sec) +Pressure : 1.6248248102E+00 (GPa) +Maximum stress : 3.4766507520E+00 (GPa) +Time for stress calculation : 0.250 (sec) +MD step time : 44.698 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.3426707392451 15.3426707392451 15.3426707392451 -CHEB_DEGREE: 25 +LATVEC_SCALE: 15.2274021817417 15.2274021817417 15.2274021817417 +CHEB_DEGREE: 35 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.306853 (Bohr) +Mesh spacing : 0.203032 (Bohr) =================================================================== - Self Consistent Field (SCF#31) + Self Consistent Field (SCF#21) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462196308E+00 1.451E-02 0.146 -2 -3.2461528473E+00 5.005E-03 0.137 -3 -3.2461498165E+00 1.790E-03 0.139 -4 -3.2461493149E+00 8.217E-04 0.137 -5 -3.2461491748E+00 1.014E-04 0.135 -6 -3.2461491734E+00 2.620E-05 0.132 -7 -3.2461491718E+00 8.740E-06 0.129 -8 -3.2461491736E+00 3.340E-06 0.127 -9 -3.2461491726E+00 1.045E-06 0.129 -10 -3.2461491729E+00 3.450E-07 0.125 +1 -3.2459392118E+00 1.434E-02 1.465 +2 -3.2458776820E+00 5.831E-03 1.451 +3 -3.2458730069E+00 2.438E-03 1.428 +4 -3.2458718426E+00 8.087E-04 1.426 +5 -3.2458717115E+00 1.108E-04 1.391 +6 -3.2458717096E+00 2.301E-05 1.394 +7 -3.2458717083E+00 1.105E-05 1.401 +8 -3.2458717097E+00 3.684E-06 1.361 +9 -3.2458717089E+00 1.303E-06 1.361 +10 -3.2458717091E+00 3.387E-07 1.329 Total number of SCF: 10 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2461491729E+00 (Ha/atom) -Total free energy : -1.0387677353E+02 (Ha) -Band structure energy : 4.3352919496E+00 (Ha) -Exchange correlation energy : -4.1721791269E+01 (Ha) -Self and correction energy : -1.6501175039E+02 (Ha) --Entropy*kb*T : -2.4364568277E-02 (Ha) -Fermi level : 1.9705647038E-01 (Ha) -RMS force : 1.3319639156E-02 (Ha/Bohr) -Maximum force : 2.7238362918E-02 (Ha/Bohr) -Time for force calculation : 0.051 (sec) -Pressure : 6.9170912408E-01 (GPa) -Maximum stress : 2.2928032066E+00 (GPa) -Time for stress calculation : 0.086 (sec) -MD step time : 1.528 (sec) +Free energy per atom : -3.2458717091E+00 (Ha/atom) +Total free energy : -1.0386789469E+02 (Ha) +Band structure energy : 5.0364043046E+00 (Ha) +Exchange correlation energy : -4.1854327342E+01 (Ha) +Self and correction energy : -1.6501201165E+02 (Ha) +-Entropy*kb*T : -2.9083198826E-02 (Ha) +Fermi level : 2.0401182803E-01 (Ha) +RMS force : 1.2324348836E-02 (Ha/Bohr) +Maximum force : 2.4047203390E-02 (Ha/Bohr) +Time for force calculation : 0.127 (sec) +Pressure : 1.4285870033E+00 (GPa) +Maximum stress : 3.2275270915E+00 (GPa) +Time for stress calculation : 0.248 (sec) +MD step time : 14.582 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.361480701113 15.361480701113 15.361480701113 -CHEB_DEGREE: 25 +LATVEC_SCALE: 15.2466719268707 15.2466719268707 15.2466719268707 +CHEB_DEGREE: 35 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.30723 (Bohr) +Mesh spacing : 0.203289 (Bohr) =================================================================== - Self Consistent Field (SCF#32) + Self Consistent Field (SCF#22) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462485229E+00 1.455E-02 0.153 -2 -3.2461812183E+00 4.940E-03 0.136 -3 -3.2461783114E+00 1.712E-03 0.138 -4 -3.2461778766E+00 8.167E-04 0.137 -5 -3.2461777383E+00 1.026E-04 0.136 -6 -3.2461777369E+00 2.691E-05 0.130 -7 -3.2461777352E+00 8.745E-06 0.129 -8 -3.2461777371E+00 3.296E-06 0.128 -9 -3.2461777356E+00 1.026E-06 0.148 -10 -3.2461777363E+00 3.613E-07 0.133 +1 -3.2459795629E+00 1.434E-02 1.468 +2 -3.2459174488E+00 5.691E-03 1.465 +3 -3.2459131007E+00 2.362E-03 1.446 +4 -3.2459120251E+00 8.085E-04 1.417 +5 -3.2459118940E+00 1.081E-04 1.429 +6 -3.2459118922E+00 2.251E-05 1.401 +7 -3.2459118909E+00 1.026E-05 1.419 +8 -3.2459118923E+00 3.607E-06 1.348 +9 -3.2459118915E+00 1.329E-06 1.420 +10 -3.2459118918E+00 3.537E-07 1.389 Total number of SCF: 10 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2461777363E+00 (Ha/atom) -Total free energy : -1.0387768756E+02 (Ha) -Band structure energy : 4.2267449659E+00 (Ha) -Exchange correlation energy : -4.1698152759E+01 (Ha) -Self and correction energy : -1.6501174359E+02 (Ha) --Entropy*kb*T : -2.4033079465E-02 (Ha) -Fermi level : 1.9593673444E-01 (Ha) -RMS force : 1.3368215470E-02 (Ha/Bohr) -Maximum force : 2.7562288854E-02 (Ha/Bohr) -Time for force calculation : 0.051 (sec) -Pressure : 5.4617759462E-01 (GPa) -Maximum stress : 2.1163149961E+00 (GPa) -Time for stress calculation : 0.086 (sec) -MD step time : 1.563 (sec) +Free energy per atom : -3.2459118918E+00 (Ha/atom) +Total free energy : -1.0386918054E+02 (Ha) +Band structure energy : 4.9286182930E+00 (Ha) +Exchange correlation energy : -4.1826842761E+01 (Ha) +Self and correction energy : -1.6501200753E+02 (Ha) +-Entropy*kb*T : -2.8437043288E-02 (Ha) +Fermi level : 2.0289697402E-01 (Ha) +RMS force : 1.2461679753E-02 (Ha/Bohr) +Maximum force : 2.4467497370E-02 (Ha/Bohr) +Time for force calculation : 0.127 (sec) +Pressure : 1.2289407179E+00 (GPa) +Maximum stress : 2.9793397170E+00 (GPa) +Time for stress calculation : 0.245 (sec) +MD step time : 14.792 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.3804233205384 15.3804233205384 15.3804233205384 -CHEB_DEGREE: 25 +LATVEC_SCALE: 15.2663923851289 15.2663923851289 15.2663923851289 +CHEB_DEGREE: 35 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.307608 (Bohr) +Mesh spacing : 0.203552 (Bohr) =================================================================== - Self Consistent Field (SCF#33) + Self Consistent Field (SCF#23) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462026628E+00 1.088E-03 0.140 -2 -3.2462040963E+00 2.184E-04 0.130 -3 -3.2462041375E+00 8.900E-05 0.220 -4 -3.2462041413E+00 3.472E-05 0.130 -5 -3.2462041420E+00 1.699E-05 0.134 -6 -3.2462041421E+00 7.393E-06 0.136 -7 -3.2462041423E+00 2.768E-06 0.127 -8 -3.2462041424E+00 6.776E-07 0.127 -9 -3.2462041423E+00 3.087E-07 0.125 +1 -3.2459463541E+00 1.825E-03 1.454 +2 -3.2459501909E+00 2.610E-04 1.418 +3 -3.2459502609E+00 1.141E-04 1.466 +4 -3.2459502676E+00 4.601E-05 1.448 +5 -3.2459502684E+00 2.784E-05 1.409 +6 -3.2459502687E+00 8.918E-06 1.426 +7 -3.2459502691E+00 3.668E-06 1.405 +8 -3.2459502691E+00 1.020E-06 1.366 +9 -3.2459502690E+00 4.302E-07 1.411 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2462041423E+00 (Ha/atom) -Total free energy : -1.0387853255E+02 (Ha) -Band structure energy : 4.1174888761E+00 (Ha) -Exchange correlation energy : -4.1674643362E+01 (Ha) -Self and correction energy : -1.6501173641E+02 (Ha) --Entropy*kb*T : -2.3752622657E-02 (Ha) -Fermi level : 1.9480589222E-01 (Ha) -RMS force : 1.3410238063E-02 (Ha/Bohr) -Maximum force : 2.7840558457E-02 (Ha/Bohr) -Time for force calculation : 0.052 (sec) -Pressure : 4.0553881347E-01 (GPa) -Maximum stress : 1.9448701209E+00 (GPa) -Time for stress calculation : 0.086 (sec) -MD step time : 1.466 (sec) +Free energy per atom : -3.2459502690E+00 (Ha/atom) +Total free energy : -1.0387040861E+02 (Ha) +Band structure energy : 4.8183677864E+00 (Ha) +Exchange correlation energy : -4.1798945105E+01 (Ha) +Self and correction energy : -1.6501200396E+02 (Ha) +-Entropy*kb*T : -2.7820508841E-02 (Ha) +Fermi level : 2.0175744881E-01 (Ha) +RMS force : 1.2587455134E-02 (Ha/Bohr) +Maximum force : 2.4856144958E-02 (Ha/Bohr) +Time for force calculation : 0.124 (sec) +Pressure : 1.0273532770E+00 (GPa) +Maximum stress : 2.7334444010E+00 (GPa) +Time for stress calculation : 0.239 (sec) +MD step time : 13.371 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.399454401535 15.399454401535 15.399454401535 -CHEB_DEGREE: 25 +LATVEC_SCALE: 15.2865134460577 15.2865134460577 15.2865134460577 +CHEB_DEGREE: 35 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.307989 (Bohr) +Mesh spacing : 0.20382 (Bohr) =================================================================== - Self Consistent Field (SCF#34) + Self Consistent Field (SCF#24) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462258306E+00 1.863E-03 0.143 -2 -3.2462284370E+00 2.306E-04 0.134 -3 -3.2462284814E+00 1.002E-04 0.131 -4 -3.2462284842E+00 3.927E-05 0.133 -5 -3.2462284847E+00 2.156E-05 0.103 -6 -3.2462284847E+00 6.097E-06 0.122 -7 -3.2462284850E+00 2.768E-06 0.129 -8 -3.2462284850E+00 9.505E-07 0.123 -9 -3.2462284849E+00 2.650E-07 0.130 +1 -3.2459825317E+00 1.845E-03 1.397 +2 -3.2459864545E+00 2.741E-04 1.406 +3 -3.2459865261E+00 1.304E-04 1.470 +4 -3.2459865308E+00 5.916E-05 1.415 +5 -3.2459865317E+00 3.050E-05 1.426 +6 -3.2459865323E+00 6.412E-06 1.421 +7 -3.2459865326E+00 4.047E-06 1.401 +8 -3.2459865325E+00 1.435E-06 1.385 +9 -3.2459865321E+00 4.812E-07 1.413 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2462284849E+00 (Ha/atom) -Total free energy : -1.0387931152E+02 (Ha) -Band structure energy : 4.0077602774E+00 (Ha) -Exchange correlation energy : -4.1651347226E+01 (Ha) -Self and correction energy : -1.6501172928E+02 (Ha) --Entropy*kb*T : -2.3524341000E-02 (Ha) -Fermi level : 1.9366613286E-01 (Ha) -RMS force : 1.3446800739E-02 (Ha/Bohr) -Maximum force : 2.8071715314E-02 (Ha/Bohr) -Time for force calculation : 0.052 (sec) -Pressure : 2.7073220393E-01 (GPa) -Maximum stress : 1.7788573122E+00 (GPa) -Time for stress calculation : 0.089 (sec) -MD step time : 2.159 (sec) +Free energy per atom : -3.2459865321E+00 (Ha/atom) +Total free energy : -1.0387156903E+02 (Ha) +Band structure energy : 4.7059398487E+00 (Ha) +Exchange correlation energy : -4.1770731415E+01 (Ha) +Self and correction energy : -1.6501200044E+02 (Ha) +-Entropy*kb*T : -2.7236343143E-02 (Ha) +Fermi level : 2.0059539845E-01 (Ha) +RMS force : 1.2701459022E-02 (Ha/Bohr) +Maximum force : 2.5213117317E-02 (Ha/Bohr) +Time for force calculation : 0.124 (sec) +Pressure : 8.2522622945E-01 (GPa) +Maximum stress : 2.4910520250E+00 (GPa) +Time for stress calculation : 0.239 (sec) +MD step time : 13.339 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.4185297446259 15.4185297446259 15.4185297446259 -CHEB_DEGREE: 25 +LATVEC_SCALE: 15.3069900700242 15.3069900700242 15.3069900700242 +CHEB_DEGREE: 35 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.308371 (Bohr) +Mesh spacing : 0.204093 (Bohr) =================================================================== - Self Consistent Field (SCF#35) + Self Consistent Field (SCF#25) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462482756E+00 1.856E-03 0.143 -2 -3.2462508729E+00 2.274E-04 0.131 -3 -3.2462509170E+00 9.549E-05 0.102 -4 -3.2462509211E+00 3.530E-05 0.122 -5 -3.2462509215E+00 1.733E-05 0.126 -6 -3.2462509216E+00 6.930E-06 0.125 -7 -3.2462509220E+00 2.700E-06 0.123 -8 -3.2462509219E+00 7.427E-07 0.123 -9 -3.2462509221E+00 2.940E-07 0.124 -Total number of SCF: 9 +1 -3.2525372635E+00 9.621E-01 1.504 +2 -3.2461891933E+00 6.296E-02 1.478 +3 -3.2461625596E+00 2.862E-02 1.450 +4 -3.2460542200E+00 1.319E-02 1.495 +5 -3.2460211530E+00 2.590E-03 1.440 +6 -3.2460203939E+00 8.958E-04 1.441 +7 -3.2460203463E+00 2.671E-04 1.433 +8 -3.2460203645E+00 9.196E-05 1.426 +9 -3.2460203717E+00 2.924E-05 1.411 +10 -3.2460203753E+00 1.255E-05 1.396 +11 -3.2460203756E+00 6.382E-06 1.405 +12 -3.2460203760E+00 2.334E-06 1.390 +13 -3.2460203764E+00 5.217E-07 1.375 +14 -3.2460203761E+00 1.370E-06 1.380 +15 -3.2460203764E+00 8.310E-07 1.380 +16 -3.2460203763E+00 6.619E-07 1.379 +17 -3.2460203764E+00 6.400E-07 1.395 +18 -3.2460203765E+00 5.037E-07 1.371 +19 -3.2460203765E+00 5.926E-07 1.328 +20 -3.2460203763E+00 5.820E-07 1.378 +21 -3.2460203765E+00 5.812E-07 1.336 +22 -3.2460203766E+00 5.046E-07 1.370 +23 -3.2460203763E+00 1.583E-07 1.343 +Total number of SCF: 23 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2462509221E+00 (Ha/atom) -Total free energy : -1.0388002951E+02 (Ha) -Band structure energy : 3.8977853494E+00 (Ha) -Exchange correlation energy : -4.1628347358E+01 (Ha) -Self and correction energy : -1.6501172237E+02 (Ha) --Entropy*kb*T : -2.3348534766E-02 (Ha) -Fermi level : 1.9251972028E-01 (Ha) -RMS force : 1.3479249429E-02 (Ha/Bohr) -Maximum force : 2.8538599095E-02 (Ha/Bohr) -Time for force calculation : 0.052 (sec) -Pressure : 1.4259414110E-01 (GPa) -Maximum stress : 1.6315602025E+00 (GPa) -Time for stress calculation : 0.087 (sec) -MD step time : 2.918 (sec) +Free energy per atom : -3.2460203763E+00 (Ha/atom) +Total free energy : -1.0387265204E+02 (Ha) +Band structure energy : 4.5915983111E+00 (Ha) +Exchange correlation energy : -4.1742286856E+01 (Ha) +Self and correction energy : -1.6501199664E+02 (Ha) +-Entropy*kb*T : -2.6687595347E-02 (Ha) +Fermi level : 1.9941271174E-01 (Ha) +RMS force : 1.2803975267E-02 (Ha/Bohr) +Maximum force : 2.5538238893E-02 (Ha/Bohr) +Time for force calculation : 0.124 (sec) +Pressure : 6.2383943594E-01 (GPa) +Maximum stress : 2.2531249136E+00 (GPa) +Time for stress calculation : 0.238 (sec) +MD step time : 32.934 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.4376148879652 15.4376148879652 15.4376148879652 -CHEB_DEGREE: 25 +LATVEC_SCALE: 15.3277799444079 15.3277799444079 15.3277799444079 +CHEB_DEGREE: 35 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.308752 (Bohr) +Mesh spacing : 0.20437 (Bohr) =================================================================== - Self Consistent Field (SCF#36) + Self Consistent Field (SCF#26) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462688058E+00 1.863E-03 0.139 -2 -3.2462714397E+00 2.349E-04 0.134 -3 -3.2462714833E+00 9.663E-05 0.133 -4 -3.2462714872E+00 3.532E-05 0.137 -5 -3.2462714878E+00 1.684E-05 0.133 -6 -3.2462714880E+00 7.018E-06 0.133 -7 -3.2462714883E+00 2.742E-06 0.134 -8 -3.2462714882E+00 7.662E-07 0.128 -9 -3.2462714884E+00 2.946E-07 0.126 +1 -3.2460493408E+00 1.176E-03 1.427 +2 -3.2460515349E+00 2.749E-04 1.386 +3 -3.2460516027E+00 1.079E-04 1.405 +4 -3.2460516097E+00 4.243E-05 1.397 +5 -3.2460516110E+00 1.360E-05 1.380 +6 -3.2460516115E+00 7.733E-06 1.363 +7 -3.2460516120E+00 3.867E-06 1.354 +8 -3.2460516120E+00 1.046E-06 1.371 +9 -3.2460516116E+00 2.798E-07 1.354 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2462714884E+00 (Ha/atom) -Total free energy : -1.0388068763E+02 (Ha) -Band structure energy : 3.7877582420E+00 (Ha) -Exchange correlation energy : -4.1605707157E+01 (Ha) -Self and correction energy : -1.6501171584E+02 (Ha) --Entropy*kb*T : -2.3224841099E-02 (Ha) -Fermi level : 1.9136868401E-01 (Ha) -RMS force : 1.3509132290E-02 (Ha/Bohr) -Maximum force : 2.9069373243E-02 (Ha/Bohr) -Time for force calculation : 0.052 (sec) -Pressure : 2.1755722878E-02 (GPa) -Maximum stress : 1.6436195738E+00 (GPa) -Time for stress calculation : 0.083 (sec) -MD step time : 1.385 (sec) +Free energy per atom : -3.2460516116E+00 (Ha/atom) +Total free energy : -1.0387365157E+02 (Ha) +Band structure energy : 4.4755903449E+00 (Ha) +Exchange correlation energy : -4.1713689494E+01 (Ha) +Self and correction energy : -1.6501199246E+02 (Ha) +-Entropy*kb*T : -2.6177507602E-02 (Ha) +Fermi level : 1.9821111870E-01 (Ha) +RMS force : 1.2895485282E-02 (Ha/Bohr) +Maximum force : 2.5830869669E-02 (Ha/Bohr) +Time for force calculation : 0.124 (sec) +Pressure : 4.2431374018E-01 (GPa) +Maximum stress : 2.0203484146E+00 (GPa) +Time for stress calculation : 0.238 (sec) +MD step time : 13.023 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.4566881472941 15.4566881472941 15.4566881472941 -CHEB_DEGREE: 25 +LATVEC_SCALE: 15.3488390512027 15.3488390512027 15.3488390512027 +CHEB_DEGREE: 35 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.309134 (Bohr) +Mesh spacing : 0.204651 (Bohr) =================================================================== - Self Consistent Field (SCF#37) + Self Consistent Field (SCF#27) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462875547E+00 1.882E-03 0.137 -2 -3.2462902525E+00 2.472E-04 0.130 -3 -3.2462902967E+00 1.070E-04 0.135 -4 -3.2462902993E+00 3.948E-05 0.133 -5 -3.2462902998E+00 1.966E-05 0.129 -6 -3.2462902999E+00 6.138E-06 0.131 -7 -3.2462903000E+00 3.042E-06 0.130 -8 -3.2462903002E+00 1.045E-06 0.123 -9 -3.2462903000E+00 2.739E-07 0.128 +1 -3.2460779156E+00 1.157E-03 1.405 +2 -3.2460801283E+00 2.712E-04 1.385 +3 -3.2460801972E+00 1.097E-04 1.416 +4 -3.2460802042E+00 4.518E-05 1.386 +5 -3.2460802051E+00 2.316E-05 1.393 +6 -3.2460802058E+00 9.361E-06 1.318 +7 -3.2460802061E+00 3.970E-06 1.374 +8 -3.2460802063E+00 9.115E-07 1.356 +9 -3.2460802063E+00 4.156E-07 1.352 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2462903000E+00 (Ha/atom) -Total free energy : -1.0388128960E+02 (Ha) -Band structure energy : 3.6778183256E+00 (Ha) -Exchange correlation energy : -4.1583460155E+01 (Ha) -Self and correction energy : -1.6501170990E+02 (Ha) --Entropy*kb*T : -2.3152177047E-02 (Ha) -Fermi level : 1.9021458186E-01 (Ha) -RMS force : 1.3537974794E-02 (Ha/Bohr) -Maximum force : 2.9557832141E-02 (Ha/Bohr) -Time for force calculation : 0.050 (sec) -Pressure : -9.1495140231E-02 (GPa) -Maximum stress : 1.6532547062E+00 (GPa) -Time for stress calculation : 0.083 (sec) -MD step time : 1.370 (sec) +Free energy per atom : -3.2460802063E+00 (Ha/atom) +Total free energy : -1.0387456660E+02 (Ha) +Band structure energy : 4.3581686981E+00 (Ha) +Exchange correlation energy : -4.1685021351E+01 (Ha) +Self and correction energy : -1.6501198792E+02 (Ha) +-Entropy*kb*T : -2.5709340758E-02 (Ha) +Fermi level : 1.9699243689E-01 (Ha) +RMS force : 1.2976360606E-02 (Ha/Bohr) +Maximum force : 2.6091449268E-02 (Ha/Bohr) +Time for force calculation : 0.124 (sec) +Pressure : 2.2782399425E-01 (GPa) +Maximum stress : 1.7934641665E+00 (GPa) +Time for stress calculation : 0.238 (sec) +MD step time : 13.041 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.4757345260545 15.4757345260545 15.4757345260545 -CHEB_DEGREE: 25 +LATVEC_SCALE: 15.3701191882507 15.3701191882507 15.3701191882507 +CHEB_DEGREE: 35 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.309515 (Bohr) +Mesh spacing : 0.204935 (Bohr) =================================================================== - Self Consistent Field (SCF#38) + Self Consistent Field (SCF#28) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2463048626E+00 1.877E-03 0.139 -2 -3.2463075835E+00 2.262E-04 0.130 -3 -3.2463076283E+00 9.394E-05 0.129 -4 -3.2463076322E+00 3.358E-05 0.133 -5 -3.2463076328E+00 1.115E-05 0.130 -6 -3.2463076329E+00 5.381E-06 0.133 -7 -3.2463076337E+00 2.558E-06 0.131 -8 -3.2463076333E+00 6.948E-07 0.124 -9 -3.2463076335E+00 2.840E-07 0.129 +1 -3.2461018922E+00 1.903E-03 1.412 +2 -3.2461061211E+00 2.739E-04 1.435 +3 -3.2461061920E+00 1.178E-04 1.381 +4 -3.2461061985E+00 4.686E-05 1.425 +5 -3.2461061992E+00 2.679E-05 1.389 +6 -3.2461061999E+00 8.680E-06 1.411 +7 -3.2461062001E+00 3.832E-06 1.369 +8 -3.2461062003E+00 9.869E-07 1.357 +9 -3.2461062002E+00 3.869E-07 1.343 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2463076335E+00 (Ha/atom) -Total free energy : -1.0388184427E+02 (Ha) -Band structure energy : 3.5680706435E+00 (Ha) -Exchange correlation energy : -4.1561624266E+01 (Ha) -Self and correction energy : -1.6501170464E+02 (Ha) --Entropy*kb*T : -2.3128519757E-02 (Ha) -Fermi level : 1.8905884717E-01 (Ha) -RMS force : 1.3567215495E-02 (Ha/Bohr) -Maximum force : 3.0001314471E-02 (Ha/Bohr) -Time for force calculation : 0.050 (sec) -Pressure : -1.9713627212E-01 (GPa) -Maximum stress : 1.6605532588E+00 (GPa) -Time for stress calculation : 0.082 (sec) -MD step time : 1.367 (sec) +Free energy per atom : -3.2461062002E+00 (Ha/atom) +Total free energy : -1.0387539841E+02 (Ha) +Band structure energy : 4.2395985357E+00 (Ha) +Exchange correlation energy : -4.1656372378E+01 (Ha) +Self and correction energy : -1.6501198334E+02 (Ha) +-Entropy*kb*T : -2.5286237160E-02 (Ha) +Fermi level : 1.9575870381E-01 (Ha) +RMS force : 1.3047325514E-02 (Ha/Bohr) +Maximum force : 2.6319421457E-02 (Ha/Bohr) +Time for force calculation : 0.124 (sec) +Pressure : 3.5504756102E-02 (GPa) +Maximum stress : 1.8154231491E+00 (GPa) +Time for stress calculation : 0.239 (sec) +MD step time : 13.088 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.4947357134871 15.4947357134871 15.4947357134871 -CHEB_DEGREE: 25 +LATVEC_SCALE: 15.3915698528554 15.3915698528554 15.3915698528554 +CHEB_DEGREE: 35 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.309895 (Bohr) +Mesh spacing : 0.205221 (Bohr) =================================================================== - Self Consistent Field (SCF#39) + Self Consistent Field (SCF#29) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2463208982E+00 1.872E-03 0.139 -2 -3.2463236206E+00 2.515E-04 0.135 -3 -3.2463236653E+00 1.172E-04 0.134 -4 -3.2463236673E+00 4.426E-05 0.128 -5 -3.2463236677E+00 2.081E-05 0.134 -6 -3.2463236677E+00 4.752E-06 0.129 -7 -3.2463236679E+00 2.813E-06 0.132 -8 -3.2463236677E+00 1.080E-06 0.129 -9 -3.2463236679E+00 2.935E-07 0.130 +1 -3.2461253180E+00 1.921E-03 1.427 +2 -3.2461296251E+00 2.722E-04 1.426 +3 -3.2461296968E+00 1.171E-04 1.441 +4 -3.2461297036E+00 4.578E-05 1.378 +5 -3.2461297046E+00 2.338E-05 1.390 +6 -3.2461297049E+00 8.945E-06 1.390 +7 -3.2461297056E+00 3.923E-06 1.397 +8 -3.2461297055E+00 1.004E-06 1.380 +9 -3.2461297053E+00 4.117E-07 1.387 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2463236679E+00 (Ha/atom) -Total free energy : -1.0388235737E+02 (Ha) -Band structure energy : 3.4586316443E+00 (Ha) -Exchange correlation energy : -4.1540224994E+01 (Ha) -Self and correction energy : -1.6501169965E+02 (Ha) --Entropy*kb*T : -2.3150881461E-02 (Ha) -Fermi level : 1.8790324749E-01 (Ha) -RMS force : 1.3598296915E-02 (Ha/Bohr) -Maximum force : 3.0397662611E-02 (Ha/Bohr) -Time for force calculation : 0.050 (sec) -Pressure : -2.9509087057E-01 (GPa) -Maximum stress : 1.6656384166E+00 (GPa) -Time for stress calculation : 0.082 (sec) -MD step time : 1.380 (sec) +Free energy per atom : -3.2461297053E+00 (Ha/atom) +Total free energy : -1.0387615057E+02 (Ha) +Band structure energy : 4.1201493017E+00 (Ha) +Exchange correlation energy : -4.1627836279E+01 (Ha) +Self and correction energy : -1.6501197907E+02 (Ha) +-Entropy*kb*T : -2.4911058730E-02 (Ha) +Fermi level : 1.9451205793E-01 (Ha) +RMS force : 1.3109176580E-02 (Ha/Bohr) +Maximum force : 2.6514457234E-02 (Ha/Bohr) +Time for force calculation : 0.121 (sec) +Pressure : -1.5152832605E-01 (GPa) +Maximum stress : 1.9010381196E+00 (GPa) +Time for stress calculation : 0.232 (sec) +MD step time : 13.179 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.51366451106 15.51366451106 15.51366451106 -CHEB_DEGREE: 25 +LATVEC_SCALE: 15.4131432377776 15.4131432377776 15.4131432377776 +CHEB_DEGREE: 35 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.310273 (Bohr) +Mesh spacing : 0.205509 (Bohr) =================================================================== - Self Consistent Field (SCF#40) + Self Consistent Field (SCF#30) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2463357407E+00 1.881E-03 0.138 -2 -3.2463384471E+00 2.667E-04 0.131 -3 -3.2463384917E+00 1.317E-04 0.129 -4 -3.2463384923E+00 4.799E-05 0.131 -5 -3.2463384931E+00 1.949E-05 0.131 -6 -3.2463384928E+00 4.761E-06 0.124 -7 -3.2463384933E+00 2.842E-06 0.126 -8 -3.2463384931E+00 1.157E-06 0.134 -9 -3.2463384929E+00 3.246E-07 0.123 +1 -3.2461464472E+00 1.932E-03 1.426 +2 -3.2461508465E+00 2.823E-04 1.433 +3 -3.2461509185E+00 1.245E-04 1.412 +4 -3.2461509242E+00 5.095E-05 1.391 +5 -3.2461509250E+00 2.837E-05 1.407 +6 -3.2461509258E+00 7.422E-06 1.367 +7 -3.2461509258E+00 3.919E-06 1.414 +8 -3.2461509260E+00 1.150E-06 1.386 +9 -3.2461509257E+00 3.754E-07 1.360 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2463384929E+00 (Ha/atom) -Total free energy : -1.0388283177E+02 (Ha) -Band structure energy : 3.3496451230E+00 (Ha) -Exchange correlation energy : -4.1519306381E+01 (Ha) -Self and correction energy : -1.6501169530E+02 (Ha) --Entropy*kb*T : -2.3215208889E-02 (Ha) -Fermi level : 1.8675014342E-01 (Ha) -RMS force : 1.3632538273E-02 (Ha/Bohr) -Maximum force : 3.0745965048E-02 (Ha/Bohr) -Time for force calculation : 0.050 (sec) -Pressure : -3.8515418103E-01 (GPa) -Maximum stress : 1.6687139585E+00 (GPa) -Time for stress calculation : 0.083 (sec) -MD step time : 1.364 (sec) +Free energy per atom : -3.2461509257E+00 (Ha/atom) +Total free energy : -1.0387682962E+02 (Ha) +Band structure energy : 4.0000742925E+00 (Ha) +Exchange correlation energy : -4.1599501030E+01 (Ha) +Self and correction energy : -1.6501197517E+02 (Ha) +-Entropy*kb*T : -2.4586290997E-02 (Ha) +Fermi level : 1.9325451517E-01 (Ha) +RMS force : 1.3162807591E-02 (Ha/Bohr) +Maximum force : 2.6675845819E-02 (Ha/Bohr) +Time for force calculation : 0.118 (sec) +Pressure : -3.3211678799E-01 (GPa) +Maximum stress : 1.9889295506E+00 (GPa) +Time for stress calculation : 0.224 (sec) *************************************************************************** Timing info *************************************************************************** -Total walltime : 20.183 sec +Total walltime : 199.540 sec ___________________________________________________________________________ *************************************************************************** diff --git a/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.restart b/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.restart index 3923abee..f68613cb 100644 --- a/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.restart +++ b/tests/Al16Si16_NPTNP_restart/high_accuracy/Al16Si16_NPTNP_restart.restart @@ -1,81 +1,132 @@ -:MDSTEP: 30 +:MDSTEP: 20 :R(Bohr): - 3.6120769897E-01 3.9317085167E-01 2.2867950980E-01 - 3.8877728998E+00 1.5292220902E+01 4.0899701582E+00 - 7.9696114472E+00 1.5135939674E+01 1.1097530692E-01 - 1.1340682528E+01 1.5296028161E+01 3.6197149122E+00 - 1.4993872519E-01 7.8947833331E+00 1.5301177253E+01 - 3.7258402024E+00 7.8911692518E+00 3.7988950316E+00 - 7.2637456045E+00 7.3964699750E+00 1.5150052913E-01 - 1.1504919160E+01 7.7623127682E+00 4.0247713665E+00 - 5.6082198546E-01 1.5120364182E+01 7.7222062190E+00 - 3.6330380446E+00 3.2134592392E-02 1.1200392685E+01 - 7.6769658828E+00 4.9152500503E-02 7.7898526685E+00 - 1.1558111670E+01 1.5125284029E+01 1.1727978355E+01 - 2.9069358211E-01 7.6817226886E+00 7.8612199041E+00 - 4.2171723953E+00 7.8648785205E+00 1.1457650079E+01 - 7.3034647061E+00 7.9858402672E+00 7.5154678782E+00 - 1.1506356288E+01 7.2480914413E+00 1.1463274360E+01 - 9.2351350990E-02 3.9220706584E+00 3.9277178144E+00 - 3.7104661706E+00 3.8592521142E+00 1.0696516851E-02 - 7.8256576260E+00 3.6238907533E+00 3.4063802372E+00 - 1.1344321889E+01 3.8024412073E+00 1.5164036487E+01 - 3.3509794581E-01 1.1399163620E+01 3.9089049236E+00 - 3.6067147244E+00 1.1538774284E+01 4.9390855581E-01 - 7.8238447845E+00 1.1670810029E+01 3.8375755438E+00 - 1.1017574921E+01 1.1480651023E+01 7.5921931343E-02 - 1.4248082818E-01 3.6977067482E+00 1.1213275946E+01 - 3.8086687480E+00 3.6877017157E+00 7.9525271672E+00 - 7.9090209069E+00 3.7600974033E+00 1.1512603725E+01 - 1.1338447542E+01 3.9571005515E+00 7.8096128199E+00 - 3.0199738312E-01 1.1500733191E+01 1.1483221375E+01 - 3.6777605257E+00 1.1218705341E+01 7.8193731285E+00 - 7.8382874678E+00 1.1721475531E+01 1.1683617103E+01 - 1.1602978167E+01 1.1508310339E+01 7.8150444651E+00 + 3.7827678095E-01 2.7577317121E-01 1.5858841243E-01 + 3.8307092758E+00 1.5185075920E+01 3.9858789816E+00 + 7.8281950745E+00 1.5075590422E+01 1.7580512791E-01 + 1.1293584727E+01 1.5189817555E+01 3.6484629030E+00 + 1.0423254155E-01 7.7714209934E+00 1.5193223522E+01 + 3.7323504950E+00 7.7628577620E+00 3.7785006822E+00 + 7.3195779770E+00 7.4172989322E+00 1.0272035466E-01 + 1.1415408068E+01 7.6740588015E+00 3.9386119308E+00 + 5.3218152134E-01 1.5066872252E+01 7.6521167923E+00 + 3.6533494467E+00 2.2809980133E-02 1.1191648009E+01 + 7.6123834266E+00 3.4814175792E-02 7.7854454836E+00 + 1.1446113810E+01 1.5069497216E+01 1.1568706253E+01 + 2.0151606134E-01 7.6160152243E+00 7.7413474673E+00 + 4.0758640745E+00 7.7500310576E+00 1.1381970516E+01 + 7.3498146660E+00 7.8332129497E+00 7.5016316543E+00 + 1.1418802929E+01 7.3199554066E+00 1.1383882257E+01 + 5.8171533604E-02 3.8679323084E+00 3.8703840200E+00 + 3.7228341056E+00 3.8211981505E+00 1.5203912179E+01 + 7.7131780041E+00 3.6604663633E+00 3.5227608437E+00 + 1.1318248080E+01 3.7739798741E+00 1.5097588160E+01 + 3.0427805990E-01 1.1343323341E+01 3.8578526588E+00 + 3.6496386977E+00 1.1438862024E+01 4.8044956361E-01 + 7.7088052967E+00 1.1530637893E+01 3.8254282582E+00 + 1.1100483209E+01 1.1393824361E+01 4.2438955812E-02 + 9.5032872030E-02 3.7068366927E+00 1.1223535356E+01 + 3.7964592693E+00 3.7032500767E+00 7.7924350678E+00 + 7.7618551619E+00 3.7506323701E+00 1.1425026861E+01 + 1.1301612855E+01 3.8912710805E+00 7.6992345023E+00 + 2.8982660840E-01 1.1408931344E+01 1.1414781652E+01 + 3.7184028262E+00 1.1216161807E+01 7.8656691969E+00 + 7.7072060211E+00 1.1564860043E+01 1.1550325002E+01 + 1.1489801633E+01 1.1416912387E+01 7.6961435808E+00 :V(Bohr/atu): - -9.1529388369E-05 4.9937895022E-04 3.0227568680E-04 - 1.4522732637E-04 -3.5091176190E-05 3.1482675405E-04 - 3.2913872033E-04 -2.2984177783E-04 -3.0647417203E-04 - -1.5203444819E-04 -4.2547139390E-05 -2.3112073250E-04 - 1.9470432371E-04 2.7192298691E-04 -3.3206997879E-05 - -1.6096894699E-04 3.0958107476E-04 -3.4857064423E-05 - -4.7128991859E-04 -3.3172117415E-04 2.1219609575E-04 - 1.3526893442E-05 1.3517967390E-04 2.4772134530E-04 - 6.2379064867E-05 -2.6928657145E-04 3.4942101255E-05 - -1.8391317213E-04 3.3170015120E-05 -3.0312471259E-04 - 3.3464241271E-05 6.2943162925E-05 -2.3647055374E-04 - 1.2554901624E-04 -2.5830542977E-04 3.1200071857E-04 - 3.7935707751E-04 3.9473550246E-05 2.7117899474E-04 - 4.7667016416E-04 2.3700699101E-04 -4.3290006885E-05 - -4.3148896368E-04 3.9986709812E-04 -1.9313325110E-04 - 1.2646696361E-06 -5.6406220843E-04 -2.5664324187E-05 - 1.6808253647E-04 1.0601069167E-04 1.1870001333E-04 - -1.9063493691E-04 4.1476732747E-05 8.9350946697E-05 - 2.4116162714E-04 -2.9142460124E-04 -6.5864933786E-04 - -2.9741723197E-04 2.0470500794E-05 -2.0988204788E-04 - 1.6507633544E-04 -1.3971668409E-04 1.0017644346E-04 - -3.1150650482E-04 5.8485245470E-05 7.2848822450E-05 - 2.5558564490E-04 2.2920129072E-04 -1.0497049798E-04 - -7.7590596399E-04 5.0854361930E-06 1.5741260180E-04 - 2.1046518603E-04 -1.5736582854E-04 -4.4483553893E-04 - -9.3041027145E-05 -1.9373532209E-04 4.6185996582E-04 - 4.1674167033E-04 -8.0574459774E-05 -3.9934246216E-06 - -2.2054761070E-04 1.5443480548E-04 2.5103991351E-04 - 6.2898520017E-05 3.2833790569E-05 -1.0545438385E-04 - -3.5290926518E-04 -3.5722882203E-04 -4.7319045606E-04 - 3.5427447074E-04 3.0575718755E-04 1.8512657564E-04 - 1.0823043398E-04 1.8745804259E-05 2.8796819961E-04 + -8.1378416685E-05 5.3222915348E-04 3.1138565585E-04 + 9.8122282586E-05 -3.8848932974E-05 3.4832032694E-04 + 4.0758777310E-04 -2.5316104636E-04 -2.8042618044E-04 + -1.9630538506E-04 -3.7831509451E-05 -2.7550487378E-04 + 2.0602523601E-04 3.0712492603E-04 -3.2511374883E-05 + -1.4769112485E-04 3.1228317735E-04 -4.0525033086E-05 + -5.2967244970E-04 -3.5860717738E-04 2.1379166719E-04 + 1.3272312518E-05 1.3346018814E-04 2.5946426587E-04 + 1.7076354410E-04 -2.7461893992E-04 7.5130098625E-05 + -2.5076151931E-04 4.7137719585E-05 -3.8355778244E-04 + 2.4451186121E-05 6.5021855749E-05 -2.4911450288E-04 + 9.6402038255E-05 -2.6661108602E-04 3.2592322874E-04 + 4.0123722827E-04 3.0676378074E-05 2.7343785320E-04 + 5.1506092383E-04 2.6728384081E-04 -5.2278503288E-05 + -4.8410567295E-04 4.3470785775E-04 -1.9375189412E-04 + 1.0822208135E-05 -5.7189650569E-04 -3.7380540811E-05 + 1.3143693530E-04 1.1761126566E-04 1.3262031508E-04 + -1.6967368741E-04 3.9324611554E-05 4.1228862593E-05 + 2.3687014266E-04 -2.8240340058E-04 -6.1005062683E-04 + -2.2925177271E-04 -2.5615000702E-05 -2.2104371556E-04 + 8.1104798983E-05 -1.3121022414E-04 9.5079280279E-05 + -3.1733697052E-04 5.7808137416E-05 1.0150008453E-05 + 2.4383557923E-04 2.4074739599E-04 -3.6524889030E-05 + -7.0209187419E-04 -4.7233057240E-06 1.3207312005E-04 + 2.0232652110E-04 -1.7696416181E-04 -4.0055887397E-04 + -4.8814058320E-05 -1.9626782822E-04 4.2939822290E-04 + 3.6321156385E-04 -9.0979389566E-05 1.5025917690E-05 + -2.1521230156E-04 1.7122151555E-04 2.0806420218E-04 + 2.0814697032E-05 1.3280455585E-05 -4.9912039470E-05 + -2.5307609297E-04 -3.7998049727E-04 -4.7175674688E-04 + 2.8346704190E-04 3.1053870598E-04 2.2857094476E-04 + 1.2853231713E-04 2.2162710273E-05 2.4554341504E-04 +:Pm_ion: + -6.1104516878E+01 3.9963428408E+02 2.3380978445E+02 + 7.3676963950E+01 -2.9170453018E+01 2.6154287787E+02 + 3.0604495608E+02 -1.9009073978E+02 -2.1056327923E+02 + -1.4739959566E+02 -2.8406501403E+01 -2.0686802343E+02 + 1.5469792881E+02 2.3061053521E+02 -2.4411778162E+01 + -1.1089666276E+02 2.3448370537E+02 -3.0428984355E+01 + -3.9771453489E+02 -2.6926695327E+02 1.6052949994E+02 + 9.9657658295E+00 1.0021109590E+02 1.9482363087E+02 + 1.2822102331E+02 -2.0620280331E+02 5.6412849580E+01 + -1.8828900970E+02 3.5394244559E+01 -2.8800158501E+02 + 1.8359633622E+01 4.8822885034E+01 -1.8705231640E+02 + 7.2385286094E+01 -2.0018995539E+02 2.4472559485E+02 + 3.0127652989E+02 2.3033936247E+01 2.0531596210E+02 + 3.8674319550E+02 2.0069510599E+02 -3.9254298826E+01 + -3.6349986236E+02 3.2640858243E+02 -1.4548225889E+02 + 8.1260588078E+00 -4.2941926260E+02 -2.8067883106E+01 + 1.0272809190E+02 9.1922265833E+01 1.0365299437E+02 + -1.3261305974E+02 3.0735213814E+01 3.2223532720E+01 + 1.8513226688E+02 -2.2072001618E+02 -4.7680156808E+02 + -1.7917792378E+02 -2.0020096635E+01 -1.7276269470E+02 + 6.3389649372E+01 -1.0255089966E+02 7.4311783212E+01 + -2.4802329266E+02 4.5181513396E+01 7.9330136448E+00 + 1.9057629222E+02 1.8816263908E+02 -2.8547014948E+01 + -5.4873889450E+02 -3.6916273448E+00 1.0322531930E+02 + 1.5813376511E+02 -1.3831112720E+02 -3.1306762229E+02 + -3.8151947605E+01 -1.5339842981E+02 3.3560779550E+02 + 2.8387782189E+02 -7.1107402731E+01 1.1743912393E+01 + -1.6820499536E+02 1.3382280669E+02 1.6261820495E+02 + 1.6268289463E+01 1.0379699273E+01 -3.9010104471E+01 + -1.9779846568E+02 -2.9698403538E+02 -3.6871424563E+02 + 2.2155133383E+02 2.4270992513E+02 1.7864580428E+02 + 1.0045790900E+02 1.7321865672E+01 1.9191109750E+02 :NPT_NP_QMASS: 500 :NPT_NP_BMASS: 0.1 -:NPT_NP_Sv: 6.90592967649367e-05 -:NPT_NP_Pm: 0.515023200248996 0.515023200248996 0.515023200248996 -:NPT_NP_S: 1.03446317630513 -:NPT_NP_range_x_velo: 0.000740274731460232 -:NPT_NP_range_y_velo: 0.000740274731460232 -:NPT_NP_range_z_velo: 0.000740274731460232 -:LATVEC_SCALE: 15.3240291435853 15.3240291435853 15.3240291435853 +:NPT_NP_SNOSE[0]: 1.00620761463942 +:NPT_NP_SNOSE[1]: 4.28455401924522e-05 +:NPT_NP_SNOSE[2]: 1.0051388092019 +:NPT_NP_INIT_Hamiltonian: -103.682126496114 +:KE: 0.164826309647071 +:Kbaro: 0.016966784086827 +:Ubaro: 0 +:kinetic_stress: + 0.000273760628000005 -9.09750341988197e-07 3.94379926444608e-06 + -9.09750341988197e-07 0.000209936358743251 4.53803829818079e-05 + 3.94379926444608e-06 4.53803829818079e-05 0.000230612779741152 +:Pm_metric_tensor: + 0.519235811582837 0.000985634825684522 -0.00374618167460646 + 0.000985634825684522 0.502333738763968 0.000417945931660174 + -0.00374618167460646 0.000417945931660174 0.516417798251566 +:LATVEC_SCALE: 1.5208636471E+01 1.5208636471E+01 1.5208636471E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:INITIAL_ANGLES: 9.0000000000E+01 9.0000000000E+01 9.0000000000E+01 +:ROTATION_MATRIX: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 :TTHRMI(K): 1120 -:TARGET_PRESSURE: 0 GPa -:NPT_NP_ini_Hamiltonian: -103.68207963937 -:TEL(K): 1120 -:TIO(K): 1122.49944988328 +:EXTERNAL_PRESSURE: 0 +:EXTERNAL_STRESS: 0 0 0 0 0 0 GPa +:TEL(K): 1.1200000000E+03 +:TIO(K): 1.1193125165E+03 diff --git a/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.inpt b/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.inpt index 24e12e06..68340fe1 100644 --- a/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.inpt +++ b/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.inpt @@ -4,7 +4,7 @@ LATVEC: 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 -MESH_SPACING: 0.35 +MESH_SPACING: 0.25 BC: P P P KPOINT_GRID: 1 1 1 # SPIN_TYP: 1 @@ -28,7 +28,7 @@ MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whichev #TWTIME: 1400 RESTART_FLAG: 1 # 1 = restart MD from .restart file if present, 0 = start new #ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) -TARGET_PRESSURE: 0 GPa +EXTERNAL_PRESSURE: 0 GPa NPT_NP_QMASS: 500.0 NPT_NP_BMASS: 0.1 NPT_SCALE_CONSTRAINTS: 123 diff --git a/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.refaimd b/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.refaimd index 4eef1c82..e3dd33b4 100644 --- a/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.refaimd +++ b/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.refaimd @@ -14,12 +14,21 @@ :Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom :Desc_UEN: Internal energy. Unit=Ha/atom :Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom -:Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 -:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom +:Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree +:Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 +:Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 +:Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during NPT_NP ensemble (has same magnitude as initial LatVec). Unit = Bohr +:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha +:Desc_SNOSE[0]: Position variable of the thermostat +:Desc_SNOSE[1]: Velocity variable of the thermostat :Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) :Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) :Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa :Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa +:Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa +:Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa :Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa where N = number of particles, k = Boltzmann constant, V = volume :Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu @@ -27,1273 +36,1493 @@ :Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr -:MDSTEP: 31 -:MDTM: 1.45 + + +:MDSTEP: 21 +:MDTM: 14.26 :TWIST: 0 :TEL: 1120 -:TIO: 1122.80973922564 -:TEN: -3.2409665447E+00 -:KEN: 5.1669156018E-03 -:KENIG: 5.3335902986E-03 -:FEN: -3.2461334603E+00 -:UEN: -3.2453720689E+00 -:TSEN: -7.6139135395E-04 -:NPT_NP_HAMIL: -9.5676289410E-06 +:TIO: 1116.0887669174 +:TEN: -3.2406988499E+00 +:KEN: 5.1359872125E-03 +:KENIG: 5.3016642194E-03 +:FEN: -3.2458348371E+00 +:UEN: -3.2449047331E+00 +:TSEN: -9.3010404132E-04 +:NPT_NP_HAMIL: -8.1138360390E-04 +:SNOSE[0]: 1.0073948300E+00 +:SNOSE[1]: 5.0555337068E-05 :R: - 3.5936371586E-01 4.0594981396E-01 2.3643308065E-01 - 3.8962365243E+00 1.5309948497E+01 4.1026620789E+00 - 7.9872134552E+00 1.5148725927E+01 1.0342758668E-01 - 1.1350835325E+01 1.5313557647E+01 3.6185163765E+00 - 1.5491919386E-01 7.9110387474E+00 1.5318955918E+01 - 3.7263363548E+00 7.9084464363E+00 3.8026542393E+00 - 7.2610408492E+00 7.3973072282E+00 1.5693285903E-01 - 1.1519255610E+01 7.7751207874E+00 4.0358006184E+00 - 5.6273616587E-01 1.5132069576E+01 7.7323358670E+00 - 3.6330934084E+00 3.2935647439E-02 1.1206743093E+01 - 7.6871541436E+00 5.0782606073E-02 7.7935075609E+00 - 1.1575383701E+01 1.5137279369E+01 1.1749931007E+01 - 3.0037660875E-01 7.6920641689E+00 7.8775034502E+00 - 4.2340405515E+00 7.8802456248E+00 1.1470550643E+01 - 7.3018027805E+00 8.0053716558E+00 7.5197954119E+00 - 1.1520369305E+01 7.2429355270E+00 1.1476612336E+01 - 9.6759707672E-02 3.9294494404E+00 3.9353932665E+00 - 3.7101748459E+00 3.8649864720E+00 1.3053638210E-02 - 7.8411608184E+00 3.6210222299E+00 3.3940467961E+00 - 1.1350530526E+01 3.8077100761E+00 1.5177298720E+01 - 3.3982735553E-01 1.1409526789E+01 3.9161679922E+00 - 3.6033942353E+00 1.1554265723E+01 4.9649371218E-01 - 7.8397098155E+00 1.1690655052E+01 3.8394628635E+00 - 1.1011548264E+01 1.1494738154E+01 7.9977413561E-02 - 1.4788201151E-01 3.6983524106E+00 1.1215748997E+01 - 3.8108736668E+00 3.6873870716E+00 7.9737163561E+00 - 7.9291311499E+00 3.7626861048E+00 1.1526456704E+01 - 1.1346741091E+01 3.9656893267E+00 7.8254695536E+00 - 3.0403534434E-01 1.1515602568E+01 1.1494425197E+01 - 3.6731836615E+00 1.1223568911E+01 7.8171221628E+00 - 7.8567873810E+00 1.1743311038E+01 1.1702307133E+01 - 1.1619739252E+01 1.1522751005E+01 7.8317979269E+00 + 3.7831751173E-01 2.7557410771E-01 1.5848196464E-01 + 3.8307019399E+00 1.5185272061E+01 3.9857855576E+00 + 7.8280918133E+00 1.5075872168E+01 1.7588105057E-01 + 1.1293823858E+01 1.5190005016E+01 3.6486358936E+00 + 1.0415135073E-01 7.7713669272E+00 1.5193405045E+01 + 3.7324470235E+00 7.7628177202E+00 3.7785584209E+00 + 7.3198748184E+00 7.4175363575E+00 1.0263692809E-01 + 1.1415544017E+01 7.6740825495E+00 3.9385455216E+00 + 5.3209306376E-01 1.5067160652E+01 7.6521441620E+00 + 3.6535114566E+00 2.2793955436E-02 1.1191959258E+01 + 7.6124803332E+00 3.4779647018E-02 7.7856252630E+00 + 1.1446222187E+01 1.5069776342E+01 1.1568714357E+01 + 2.0136669992E-01 7.6160935305E+00 7.7413291235E+00 + 4.0757260493E+00 7.7499904251E+00 1.1382142238E+01 + 7.3500911393E+00 7.8331274368E+00 7.5018172123E+00 + 1.1418907681E+01 7.3202601330E+00 1.1384034308E+01 + 5.8123667677E-02 3.8679209456E+00 3.8703733184E+00 + 3.7229355180E+00 3.8212161310E+00 1.5204097185E+01 + 7.7131925852E+00 3.6606217154E+00 3.5230047856E+00 + 1.1318458711E+01 3.7740588202E+00 1.5097854782E+01 + 3.0428010409E-01 1.1343514057E+01 3.8578407290E+00 + 3.6497967126E+00 1.1438979423E+01 4.8048939848E-01 + 7.7088133463E+00 1.1530665264E+01 3.8254313409E+00 + 1.1100831196E+01 1.1393952021E+01 4.2414574372E-02 + 9.4960523666E-02 3.7069589955E+00 1.1223806481E+01 + 3.7964961727E+00 3.7033629933E+00 7.7923875869E+00 + 7.7618199903E+00 3.7507178690E+00 1.1425138396E+01 + 1.1301817085E+01 3.8912433990E+00 7.6992407028E+00 + 2.8983493010E-01 1.1409064949E+01 1.1414886556E+01 + 3.7185016263E+00 1.1216447047E+01 7.8659557459E+00 + 7.7072214016E+00 1.1564857746E+01 1.1550324215E+01 + 1.1489857640E+01 1.1417036675E+01 7.6961840612E+00 :V: - -9.1968170380E-05 4.9548112779E-04 3.0111435308E-04 - 1.5049056117E-04 -3.4952670677E-05 3.1090333454E-04 - 3.1865506727E-04 -2.2633605562E-04 -3.0945917692E-04 - -1.4651784799E-04 -4.3118984324E-05 -2.2557332890E-04 - 1.9327007464E-04 2.6807916231E-04 -3.3334219404E-05 - -1.6250907817E-04 3.0941327320E-04 -3.4650896596E-05 - -4.6473122669E-04 -3.2855941730E-04 2.1139462830E-04 - 1.3956037268E-05 1.3570596654E-04 2.4712421567E-04 - 4.9634089735E-05 -2.6911032415E-04 2.9785137010E-05 - -1.7571861021E-04 3.0692667457E-05 -2.9280724756E-04 - 3.4361974003E-05 6.3253423177E-05 -2.3433255432E-04 - 1.2959634517E-04 -2.5767223888E-04 3.0981243590E-04 - 3.7579568832E-04 4.0300690925E-05 2.7085627650E-04 - 4.7289240023E-04 2.3376263526E-04 -4.1566438159E-05 - -4.2467132760E-04 3.9557596988E-04 -1.9379888729E-04 - 8.5770890656E-07 -5.6269760188E-04 -2.4222879296E-05 - 1.7304596948E-04 1.0511298089E-04 1.1678630665E-04 - -1.9347576786E-04 4.1952174663E-05 9.4421350365E-05 - 2.4116535344E-04 -2.9304527050E-04 -6.6364004746E-04 - -3.0556759903E-04 2.5984828542E-05 -2.0853967591E-04 - 1.7408815038E-04 -1.4090847556E-04 1.0109689023E-04 - -3.1040923795E-04 5.8820956566E-05 7.9938587484E-05 - 2.5582907169E-04 2.2771691355E-04 -1.1194548119E-04 - -7.8240314544E-04 5.1021046998E-06 1.5963684663E-04 - 2.1058182984E-04 -1.5510878984E-04 -4.4961893569E-04 - -9.7736656758E-05 -1.9330005721E-04 4.6398416269E-04 - 4.2265499143E-04 -7.9898761416E-05 -5.8946527156E-06 - -2.2129922655E-04 1.5213593730E-04 2.5619194581E-04 - 6.7297408045E-05 3.5627441220E-05 -1.1116403152E-04 - -3.6449612458E-04 -3.5359433081E-04 -4.7366751327E-04 - 3.6125518959E-04 3.0541232504E-04 1.8056625031E-04 - 1.0681776449E-04 1.7987749999E-05 2.9204627049E-04 + -8.1914707890E-05 5.2926193184E-04 3.1005004687E-04 + 1.0025001851E-04 -3.8471445181E-05 3.4587211617E-04 + 4.0300967192E-04 -2.5151585713E-04 -2.8105481167E-04 + -1.9363173164E-04 -3.7963933843E-05 -2.7257994673E-04 + 2.0494878969E-04 3.0444702632E-04 -3.2526909022E-05 + -1.4791030275E-04 3.1139316885E-04 -3.9997964404E-05 + -5.2540001064E-04 -3.5635924575E-04 2.1328265289E-04 + 1.3207029549E-05 1.3301016268E-04 2.5801498008E-04 + 1.6504747082E-04 -2.7343744949E-04 7.3000168809E-05 + -2.4682507192E-04 4.6578496153E-05 -3.7889625671E-04 + 2.4810243248E-05 6.4605068724E-05 -2.4798281064E-04 + 9.7409162311E-05 -2.6540377553E-04 3.2466718018E-04 + 3.9947474562E-04 3.1169025326E-05 2.7260231551E-04 + 5.1169162267E-04 2.6496560938E-04 -5.1896684729E-05 + -4.8063253893E-04 4.3191666336E-04 -1.9291582535E-04 + 1.0113914607E-05 -5.7021877619E-04 -3.6617091340E-05 + 1.3269352251E-04 1.1649225673E-04 1.3176316322E-04 + -1.7009507314E-04 3.9236560019E-05 4.3875450857E-05 + 2.3675870248E-04 -2.8192651647E-04 -6.1142294215E-04 + -2.3217867505E-04 -2.3145379330E-05 -2.1997306920E-04 + 8.5855004328E-05 -1.3128450792E-04 9.4830312450E-05 + -3.1651747204E-04 5.7491813347E-05 1.3831291275E-05 + 2.4430838322E-04 2.3954918269E-04 -4.0668769005E-05 + -7.0509066679E-04 -3.7024213663E-06 1.3338879417E-04 + 2.0243409754E-04 -1.7547696062E-04 -4.0194917236E-04 + -5.1274471068E-05 -1.9579419766E-04 4.3061310886E-04 + 3.6518274505E-04 -9.0031257858E-05 1.3883266032E-05 + -2.1486366970E-04 1.7009710155E-04 2.0952226276E-04 + 2.3327469794E-05 1.4080413731E-05 -5.3243546890E-05 + -2.5796842842E-04 -3.7831213322E-04 -4.7021030817E-04 + 2.8705575299E-04 3.0946313675E-04 2.2535738958E-04 + 1.2669033175E-04 2.2015304757E-05 2.4771572736E-04 :F: - -9.8403114661E-04 -6.1189024493E-03 -1.3254523716E-03 - 1.0924456662E-02 7.8180141632E-05 -6.8300329862E-03 - -2.0480819575E-02 6.6951983727E-03 -6.9799049621E-03 - 1.0676058552E-02 -1.2669626366E-03 1.0486066134E-02 - -2.2158079267E-03 -6.6945254311E-03 -3.9592547954E-04 - -3.5752612583E-03 6.3573001419E-04 9.3520330282E-05 - 1.1472673560E-02 5.2151283464E-03 -1.1393547221E-03 - 1.0620071657E-03 1.6062044134E-03 -6.4833038365E-05 - -2.5397169882E-02 -7.3161543855E-04 -1.0347030674E-02 - 1.5942403935E-02 -5.1778529685E-03 2.0054997582E-02 - 1.9134293320E-03 1.0300970533E-03 3.6884498902E-03 - 8.8337735191E-03 3.1969002095E-04 -3.5671564875E-03 - -6.2832326916E-03 1.6165009690E-03 2.4906874914E-04 - -5.7132717278E-03 -5.5716158673E-03 3.6001957543E-03 - 1.2491862857E-02 -7.3544589915E-03 -2.2646160879E-03 - -5.5136350074E-04 1.0898824396E-03 2.8279096795E-03 - 1.1146911472E-02 -1.3255564906E-03 -3.7329468088E-03 - -6.7913833829E-03 1.2407773171E-03 1.0677468251E-02 - 8.0750915519E-04 -4.5874575404E-03 -1.2443236116E-02 - -1.8099852890E-02 1.1553823126E-02 2.1630311848E-03 - 1.8902687781E-02 -2.9695057991E-03 2.3165531658E-03 - 1.3298875820E-03 1.0321215797E-03 1.4878546396E-02 - 1.0157788829E-03 -2.3647779898E-03 -1.4479392904E-02 - -1.5304179918E-02 -5.0774104339E-04 5.0249948576E-03 - 6.4840195933E-04 4.1398671598E-03 -1.1300787131E-02 - -9.8950179237E-03 3.8585088062E-04 5.3989882106E-03 - 1.3599862295E-02 8.6741199853E-04 -3.8677609947E-03 - -2.4208226880E-03 -4.4128937425E-03 1.1504614294E-02 - 9.2552787811E-03 6.1236646691E-03 -1.1967547607E-02 - -2.5249031298E-02 6.7761480690E-03 -2.6388177041E-03 - 1.5179178217E-02 3.3463704916E-04 -8.8038962078E-03 - -2.2409158998E-03 -1.6570472312E-03 9.1842878038E-03 -:LATVEC_SCALE: 1.5342663156E+01 1.5342663156E+01 1.5342663156E+01 + -3.3298965904E-03 -4.2839263570E-03 -1.0207979165E-03 + 1.0227895462E-02 8.6380946494E-04 -4.8514095198E-03 + -1.2158542008E-02 2.7292062149E-03 -6.1744401085E-03 + 7.4265690746E-03 -1.0511791086E-03 7.4702125713E-03 + -1.2224294114E-03 -6.0021198536E-03 -4.4322162567E-04 + -2.9903855365E-03 9.4459775648E-04 1.5436526681E-03 + 9.4925657004E-03 3.7488613997E-03 1.1631203330E-03 + -3.2981638518E-04 3.4731242856E-04 -1.8343771376E-03 + -2.0142051326E-02 6.3971375521E-04 -6.9065705036E-03 + 1.1743521473E-02 -1.5424231217E-03 1.2846523212E-02 + 1.5926510067E-03 -5.9471599639E-04 8.3454355799E-04 + 5.2935519575E-03 9.1118973907E-04 -3.9069047907E-04 + -1.4470942520E-03 2.3485099097E-03 6.2425004731E-04 + -6.3684745768E-03 -5.1009331639E-03 4.4069330812E-04 + 7.0572818081E-03 -4.8878686667E-03 1.9287443438E-04 + -2.3977240385E-03 -1.5281433655E-03 2.2735153545E-03 + 7.2883947930E-03 -2.7200285931E-03 -1.5239412247E-03 + -4.2795126510E-03 2.8626254431E-04 1.1182042531E-02 + 2.7998730752E-03 -2.3203167795E-03 -1.4247234369E-02 + -1.5480089355E-02 9.5337848892E-03 1.0072005633E-03 + 2.0429238529E-02 -2.4535482994E-03 6.7153073896E-04 + -1.1682880122E-03 -4.4245929421E-04 1.4834215011E-02 + 5.4302886730E-03 -1.2397201498E-03 -1.7044974264E-02 + -2.2237184282E-02 4.1589703515E-03 7.0848772165E-03 + 3.4336359383E-03 3.3591369686E-03 -1.1606627577E-02 + -1.0529449116E-02 -8.8867250212E-04 1.0995779279E-02 + 1.3388770912E-02 2.4936399795E-03 -4.3729655193E-03 + -1.7175526653E-03 -1.9886904070E-03 9.2458035353E-03 + 1.0474331064E-02 3.4695387719E-03 -1.3923394078E-02 + -2.3544610377E-02 1.2219265247E-03 -8.6691416181E-04 + 1.8606845865E-02 3.3250124968E-04 -9.2398739563E-03 + -5.3423147488E-03 -3.4421628964E-04 1.2036598079E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5179179785E+03 +:LATVEC_SCALE: + 1.5208810074E+01 1.5208810074E+01 1.5208810074E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 :STRIO: - -1.0735127415E+00 -2.2555613885E-02 3.7370523893E-02 - -2.2555613885E-02 -7.1005018910E-01 -1.6847319139E-01 - 3.7370523893E-02 -1.6847319139E-01 -9.0102484517E-01 + 1.0557386247E+00 -2.2126050011E-03 1.2102917190E-02 + -2.2126050011E-03 8.0420190098E-01 1.7444860175E-01 + 1.2102917190E-02 1.7444860175E-01 8.8906656447E-01 :STRESS: - -2.2913279622E+00 -4.0077856434E-01 1.5599121439E+00 - -4.0077856434E-01 1.2399302179E+00 3.8950863886E-02 - 1.5599121439E+00 3.8950863886E-02 -1.0103729204E+00 -:PRESIO: 8.9486259193E-01 -:PRES: 6.8725688823E-01 -:PRESIG: 9.2690192094E-01 + -3.4690459776E+00 -3.1558124482E-01 1.2122419742E+00 + -3.1558124482E-01 1.3234447193E+00 4.4011006867E-02 + 1.2122419742E+00 4.4011006867E-02 -2.7110150322E+00 +:CONSTRESS: + 4.0193705129E+00 6.1689055216E-01 -2.3556219073E+00 + 6.1689055216E-01 -6.2447015800E+00 2.5995618851E-01 + -2.3556219073E+00 2.5995618851E-01 2.2253310671E+00 +:TOTSTRESS: + 5.0541408935E-01 -3.0352191234E-01 1.1554828503E+00 + -3.0352191234E-01 5.7254587617E+00 -1.2951859363E-01 + 1.1554828503E+00 -1.2951859363E-01 1.3747505296E+00 +:PRESIO: 9.1633569670E-01 +:PRES: 1.6188720968E+00 +:CONPRES: -3.4423613525E-14 +:TOTPRES: 2.5352077935E+00 +:PRESIG: 9.4589491272E-01 :MIND: -Al - Al: 4.8679534488E+00 -Si - Si: 4.7292695333E+00 -Al - Si: 4.7432876345E+00 -:MDSTEP: 32 -:MDTM: 1.44 +Al - Al: 4.7223495552E+00 +Si - Si: 4.7547972642E+00 +Al - Si: 4.8769539187E+00 + + +:MDSTEP: 22 +:MDTM: 6.35 :TWIST: 0 :TEL: 1120 -:TIO: 1123.13745710497 -:TEN: -3.2409961032E+00 -:KEN: 5.1684236851E-03 -:KENIG: 5.3351470298E-03 -:FEN: -3.2461645268E+00 -:UEN: -3.2454135294E+00 -:TSEN: -7.5099745445E-04 -:NPT_NP_HAMIL: -1.1656416992E-05 +:TIO: 1115.7428988694 +:TEN: -3.2407417647E+00 +:KEN: 5.1343956063E-03 +:KENIG: 5.3000212710E-03 +:FEN: -3.2458761603E+00 +:UEN: -3.2449670903E+00 +:TSEN: -9.0906999477E-04 +:NPT_NP_HAMIL: -8.1466229887E-04 +:SNOSE[0]: 1.0082839328E+00 +:SNOSE[1]: 4.2283743886E-05 :R: - 3.5751243132E-01 4.1864882071E-01 2.4416786626E-01 - 3.9048733707E+00 1.5327830791E+01 4.1153049570E+00 - 8.0046345703E+00 1.5161750877E+01 9.5798383168E-02 - 1.1361237353E+01 1.5331225183E+01 3.6174885328E+00 - 1.5987057697E-01 7.9272855712E+00 1.5336883424E+01 - 3.7268275859E+00 7.9258059849E+00 3.8064531927E+00 - 7.2585592054E+00 7.3982886786E+00 1.6234930045E-01 - 1.1533720381E+01 7.7880246107E+00 4.0468656782E+00 - 5.6433781978E-01 1.5143921336E+01 7.7424131186E+00 - 3.6333870412E+00 3.3671854331E-02 1.1213460733E+01 - 7.6974427114E+00 5.2425130031E-02 7.7972901001E+00 - 1.1592879980E+01 1.5149434091E+01 1.1771951929E+01 - 3.0997839264E-01 7.7025022040E+00 7.8938648056E+00 - 4.2508724692E+00 7.8956183868E+00 1.1483611608E+01 - 7.3003765014E+00 8.0248852086E+00 7.5241728379E+00 - 1.1534490691E+01 7.2378742761E+00 1.1490100858E+01 - 1.0130023208E-01 3.9368500240E+00 3.9430614977E+00 - 3.7098420511E+00 3.8707737611E+00 1.5537650874E-02 - 7.8567484913E+00 3.6181393223E+00 3.3816080239E+00 - 1.1356640073E+01 3.8131553695E+00 1.5190741963E+01 - 3.4478446877E-01 1.1419970613E+01 3.9234965196E+00 - 3.6001304965E+00 1.1569884270E+01 4.9926125785E-01 - 7.8556615897E+00 1.1710585191E+01 3.8412164591E+00 - 1.1005459955E+01 1.1508934128E+01 8.4091597162E-02 - 1.5328925229E-01 3.6990871462E+00 1.1218205438E+01 - 3.8129994013E+00 3.6871169001E+00 7.9950430858E+00 - 7.9494775805E+00 3.7653240871E+00 1.1540378668E+01 - 1.1355122479E+01 3.9742624819E+00 7.8415388164E+00 - 3.0618644604E-01 1.1530660150E+01 1.1505602036E+01 - 3.6683459505E+00 1.1228631527E+01 7.8149249461E+00 - 7.8755426551E+00 1.1765263414E+01 1.1721005801E+01 - 1.1636588071E+01 1.1537286797E+01 7.8487355762E+00 + 3.7673028890E-01 2.8902620933E-01 1.6636809199E-01 + 3.8379844367E+00 1.5203071879E+01 3.9992625908E+00 + 7.8476856602E+00 1.5088259865E+01 1.6908251697E-01 + 1.1303008161E+01 1.5207811289E+01 3.6464210108E+00 + 1.0936004697E-01 7.7884825047E+00 1.5211354294E+01 + 3.7333650039E+00 7.7801386614E+00 3.7822405877E+00 + 7.3159293879E+00 7.4178719091E+00 1.0806557149E-01 + 1.1429964725E+01 7.6868619203E+00 3.9498021033E+00 + 5.3672118177E-01 1.5078980320E+01 7.6633613192E+00 + 3.6519686957E+00 2.3968732091E-02 1.1196452616E+01 + 7.6225054295E+00 3.6422655672E-02 7.7890874465E+00 + 1.1462806251E+01 1.5081800371E+01 1.1591055648E+01 + 2.1152303258E-01 7.6262856732E+00 7.7576585635E+00 + 4.0934210231E+00 7.7661051435E+00 1.1394910361E+01 + 7.3472791030E+00 7.8534906158E+00 7.5062919682E+00 + 1.1433242813E+01 7.3151335874E+00 1.1397195548E+01 + 6.1533315435E-02 3.8755722203E+00 3.8784139068E+00 + 3.7232840115E+00 3.8269099839E+00 1.5224026307E+01 + 7.7286104152E+00 3.6581288918E+00 3.5120907337E+00 + 1.1326576939E+01 3.7782014601E+00 1.5111041628E+01 + 3.0690996843E-01 1.1354246208E+01 3.8649622069E+00 + 3.6464387481E+00 1.1454527819E+01 4.8151523031E-01 + 7.7244290052E+00 1.1550841554E+01 3.8290425611E+00 + 1.1096900276E+01 1.1407953377E+01 4.5820861765E-02 + 1.0012374740E-01 3.7072000975E+00 1.1227616667E+01 + 3.7998475684E+00 3.7030697444E+00 7.8127648278E+00 + 7.7805496039E+00 3.7531289426E+00 1.1439563504E+01 + 1.1310427368E+01 3.9002585819E+00 7.7140039401E+00 + 2.9083487670E-01 1.1423522269E+01 1.1427575182E+01 + 3.7165473757E+00 1.1220912073E+01 7.8639899902E+00 + 7.7239755188E+00 1.1586821288E+01 1.1570124362E+01 + 1.1507157207E+01 1.1431677882E+01 7.7119084415E+00 :V: - -9.2284759320E-05 4.9143837503E-04 2.9986205552E-04 - 1.5569687650E-04 -3.4845397529E-05 3.0686131899E-04 - 3.0772695172E-04 -2.2252624332E-04 -3.1237111200E-04 - -1.4085940157E-04 -4.3672911059E-05 -2.1985688963E-04 - 1.9177919034E-04 2.6418857156E-04 -3.3468729351E-05 - -1.6399286788E-04 3.0913199745E-04 -3.4536488484E-05 - -4.5805344199E-04 -3.2529594358E-04 2.1041034939E-04 - 1.4463471782E-05 1.3625072909E-04 2.4661135898E-04 - 3.6754134782E-05 -2.6895563030E-04 2.4519145163E-05 - -1.6735263810E-04 2.8026784720E-05 -2.8214369550E-04 - 3.5258312665E-05 6.3648998943E-05 -2.3202063054E-04 - 1.3379093108E-04 -2.5701060414E-04 3.0741488833E-04 - 3.7190279934E-04 4.1036032194E-05 2.7045530303E-04 - 4.6909771458E-04 2.3050393938E-04 -3.9673528707E-05 - -4.1755838674E-04 3.9110544799E-04 -1.9456216827E-04 - 5.7851686088E-07 -5.6105555608E-04 -2.2752397938E-05 - 1.7809997947E-04 1.0426772474E-04 1.1475423129E-04 - -1.9638388708E-04 4.2470650471E-05 9.9401140052E-05 - 2.4108719456E-04 -2.9469415528E-04 -6.6836757210E-04 - -3.1372630135E-04 3.1521383787E-05 -2.0708846083E-04 - 1.8289057438E-04 -1.4207061126E-04 1.0202064319E-04 - -3.0916294609E-04 5.9205753088E-05 8.6978024455E-05 - 2.5582312999E-04 2.2613087422E-04 -1.1872970331E-04 - -7.8828334270E-04 4.8466631230E-06 1.6175655563E-04 - 2.1048616328E-04 -1.5280547108E-04 -4.5420990532E-04 - -1.0233163665E-04 -1.9273784262E-04 4.6569330062E-04 - 4.2841011607E-04 -7.9324046377E-05 -7.7535204000E-06 - -2.2203981801E-04 1.4970636882E-04 2.6125735599E-04 - 7.1642182035E-05 3.8519411832E-05 -1.1673512614E-04 - -3.7599742259E-04 -3.4963048658E-04 -4.7402310606E-04 - 3.6789333463E-04 3.0498065298E-04 1.7595808984E-04 - 1.0552655771E-04 1.7151501627E-05 2.9591997302E-04 + -8.3340715049E-05 5.2593262577E-04 3.0886371777E-04 + 1.0522571545E-04 -3.7982768195E-05 3.4264766585E-04 + 3.9584826875E-04 -2.4955484300E-04 -2.8359015725E-04 + -1.8940730106E-04 -3.8429774618E-05 -2.6817276873E-04 + 2.0386847274E-04 3.0076006624E-04 -3.2677663002E-05 + -1.4913210043E-04 3.1123894977E-04 -3.9160102452E-05 + -5.1945359307E-04 -3.5367812633E-04 2.1336769486E-04 + 1.3045301850E-05 1.3294407797E-04 2.5658280167E-04 + 1.5442930485E-04 -2.7256859629E-04 6.9274764692E-05 + -2.4028598447E-04 4.5620918327E-05 -3.7145818048E-04 + 2.5551349630E-05 6.4209027740E-05 -2.4696036485E-04 + 9.9942428928E-05 -2.6441289461E-04 3.2371636072E-04 + 3.9780102753E-04 3.2297702578E-05 2.7233402052E-04 + 5.0740445297E-04 2.6181667295E-04 -5.1497040621E-05 + -4.7593925590E-04 4.2848786698E-04 -1.9247819272E-04 + 8.9269797423E-06 -5.6975029095E-04 -3.5378734654E-05 + 1.3605830030E-04 1.1495754310E-04 1.3070145176E-04 + -1.7185853118E-04 3.9308045539E-05 4.9192807336E-05 + 2.3753906002E-04 -2.8252407439E-04 -6.1701567177E-04 + -2.3926875234E-04 -1.8406362771E-05 -2.1900283894E-04 + 9.5593998575E-05 -1.3223014713E-04 9.5026376237E-05 + -3.1634839124E-04 5.7186354314E-05 2.1016494826E-05 + 2.4630888821E-04 2.3842503954E-04 -4.8791660640E-05 + -7.1427607381E-04 -1.7427643608E-06 1.3645321707E-04 + 2.0361859756E-04 -1.7345775204E-04 -4.0675927389E-04 + -5.6283727828E-05 -1.9581362274E-04 4.3491054814E-04 + 3.7093333776E-04 -8.8656327174E-05 1.1751083166E-05 + -2.1525134242E-04 1.6872866415E-04 2.1367132161E-04 + 2.8316991519E-05 1.5796851124E-05 -5.9840374431E-05 + -2.6891893336E-04 -3.7681826618E-04 -4.6971963179E-04 + 2.9542675409E-04 3.0899863306E-04 2.2046598491E-04 + 1.2392417865E-04 2.1769796317E-05 2.5295447164E-04 :F: - -7.9718716183E-04 -6.1713152691E-03 -1.3725268274E-03 - 1.0881090029E-02 5.2267961765E-06 -6.9285857809E-03 - -2.1251547429E-02 7.2378263237E-03 -6.9743524748E-03 - 1.0890736336E-02 -1.2463744856E-03 1.0728025587E-02 - -2.2329401442E-03 -6.6700000920E-03 -4.3281619668E-04 - -3.5228459600E-03 5.2751964648E-04 -1.0944307483E-04 - 1.1502512458E-02 5.2654416960E-03 -1.4127265447E-03 - 1.2277746183E-03 1.7016732338E-03 2.2681522320E-04 - -2.5651666358E-02 -8.9671649671E-04 -1.0543208929E-02 - 1.6209819144E-02 -5.5447533117E-03 2.0624697537E-02 - 1.9353512053E-03 1.2285942613E-03 3.9217755067E-03 - 9.2042731730E-03 2.6490757855E-04 -3.8432538281E-03 - -6.7906814901E-03 1.4287861441E-03 2.1808922002E-04 - -5.5346039404E-03 -5.4859064316E-03 3.9185488674E-03 - 1.2885825152E-02 -7.5329896199E-03 -2.5545223023E-03 - -2.8770630359E-04 1.4041138466E-03 2.8826354025E-03 - 1.1416875915E-02 -1.1750552837E-03 -3.9276913059E-03 - -7.0343216369E-03 1.3503828978E-03 1.0546954462E-02 - 7.9059184552E-04 -4.7789174729E-03 -1.2240002755E-02 - -1.8277582832E-02 1.1606752110E-02 2.3145048683E-03 - 1.8547868317E-02 -2.9624283720E-03 2.3560865867E-03 - 1.4827368207E-03 1.1637710926E-03 1.4828839424E-02 - 6.3924050423E-04 -2.4722819442E-03 -1.4152013624E-02 - -1.4404840823E-02 -1.0880626688E-03 4.9116845669E-03 - 3.0686652288E-04 4.1621292006E-03 -1.1118758094E-02 - -9.7418795300E-03 5.7669163941E-04 4.7687832531E-03 - 1.3467773080E-02 6.0900589876E-04 -3.7887002549E-03 - -2.5073730921E-03 -4.6160055957E-03 1.1414008438E-02 - 9.2112061617E-03 6.3406810858E-03 -1.1759669976E-02 - -2.5254242103E-02 7.2993039459E-03 -2.5701295841E-03 - 1.4637533809E-02 2.8349050272E-04 -8.8555639689E-03 - -1.9486562883E-03 -1.8154908560E-03 8.9225165798E-03 -:LATVEC_SCALE: 1.5361450685E+01 1.5361450685E+01 1.5361450685E+01 + -3.0189695292E-03 -4.4913215520E-03 -1.0868101174E-03 + 1.0366289984E-02 7.5345605835E-04 -5.0465878708E-03 + -1.2888714177E-02 2.9448858777E-03 -6.2491640776E-03 + 7.7187489615E-03 -1.1166869937E-03 7.7380888688E-03 + -1.3462671819E-03 -6.0797594843E-03 -4.2823813071E-04 + -3.1011762386E-03 1.0562546589E-03 1.4470183665E-03 + 9.7047658980E-03 3.9041992713E-03 9.6456196312E-04 + -2.0152954406E-04 5.0638802707E-04 -1.6861328614E-03 + -2.0625454118E-02 5.1499969269E-04 -7.2699231307E-03 + 1.2144248148E-02 -1.8678381050E-03 1.3501537096E-02 + 1.5577137006E-03 -4.3553236431E-04 1.1430740010E-03 + 5.5804237818E-03 7.9537093624E-04 -6.5908620079E-04 + -1.8445998906E-03 2.3937516110E-03 5.9834547623E-04 + -6.3570805322E-03 -5.1763739386E-03 7.1005418703E-04 + 7.5406276939E-03 -5.0992615675E-03 -7.4178469601E-05 + -2.2295947087E-03 -1.3974186672E-03 2.3352856617E-03 + 7.7743305944E-03 -2.6043480674E-03 -1.7121517382E-03 + -4.4931407313E-03 3.5180353414E-04 1.1173926122E-02 + 2.4932230938E-03 -2.6113207418E-03 -1.4204317716E-02 + -1.5845691069E-02 9.8465538423E-03 1.0804598822E-03 + 2.0564634663E-02 -2.6007177744E-03 9.6670396273E-04 + -8.9815111623E-04 -3.1770715668E-04 1.4977581886E-02 + 4.9708835859E-03 -1.3129474162E-03 -1.6876354127E-02 + -2.1878783959E-02 3.9067675372E-03 6.7436521594E-03 + 3.2295417131E-03 3.4518359325E-03 -1.1780879467E-02 + -1.0617901018E-02 -9.0188182656E-04 1.0524342029E-02 + 1.3563927744E-02 2.4015887471E-03 -4.3165553544E-03 + -1.7612398277E-03 -2.1800164877E-03 9.7288915533E-03 + 1.0347574213E-02 3.7459295185E-03 -1.3801634055E-02 + -2.3958688033E-02 1.6460447909E-03 -1.2124925122E-03 + 1.8491914833E-02 4.5114136599E-04 -9.0043925431E-03 + -4.9818669345E-03 -4.7783925847E-04 1.1775375158E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5309649266E+03 +:LATVEC_SCALE: + 1.5227588582E+01 1.5227588582E+01 1.5227588582E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0745997979E+00 -2.5102025251E-02 4.0982315833E-02 - -2.5102025251E-02 -6.9898439783E-01 -1.6731273508E-01 - 4.0982315833E-02 -1.6731273508E-01 -9.0071211845E-01 + 1.0556857725E+00 2.9132597668E-04 6.3189971023E-03 + 2.9132597668E-04 7.9368304055E-01 1.7339393291E-01 + 6.3189971023E-03 1.7339393291E-01 8.8863192026E-01 :STRESS: - -2.1146822360E+00 -4.1324843451E-01 1.5820218781E+00 - -4.1324843451E-01 1.2812961740E+00 3.9714933575E-02 - 1.5820218781E+00 3.9714933575E-02 -7.9193314906E-01 -:PRESIO: 8.9143210474E-01 -:PRES: 5.4177307036E-01 -:PRESIG: 9.2377473564E-01 + -3.2197883779E+00 -3.2135752503E-01 1.2419148878E+00 + -3.2135752503E-01 1.3599622342E+00 4.2251429870E-02 + 1.2419148878E+00 4.2251429870E-02 -2.4078715008E+00 +:CONSTRESS: + 3.9165495796E+00 6.3276824760E-01 -2.4272850494E+00 + 6.3276824760E-01 -5.9350979609E+00 2.6149821924E-01 + -2.4272850494E+00 2.6149821924E-01 2.0185483813E+00 +:TOTSTRESS: + 3.5892457087E-01 -3.1111939660E-01 1.1916891587E+00 + -3.1111939660E-01 5.3688187673E+00 -1.3035571620E-01 + 1.1916891587E+00 -1.3035571620E-01 1.2779550397E+00 +:PRESIO: 9.1266691111E-01 +:PRES: 1.4225658815E+00 +:CONPRES: 1.3290970473E-16 +:TOTPRES: 2.3352327926E+00 +:PRESIG: 9.4210777922E-01 :MIND: -Al - Al: 4.8680391631E+00 -Si - Si: 4.7270645217E+00 -Al - Si: 4.7273840799E+00 -:MDSTEP: 33 -:MDTM: 1.32 +Al - Al: 4.7135214018E+00 +Si - Si: 4.7550207481E+00 +Al - Si: 4.8728759219E+00 + + +:MDSTEP: 23 +:MDTM: 6.26 :TWIST: 0 :TEL: 1120 -:TIO: 1122.96666703045 -:TEN: -3.2410260252E+00 -:KEN: 5.1676377479E-03 -:KENIG: 5.3343357398E-03 -:FEN: -3.2461936629E+00 -:UEN: -3.2454514636E+00 -:TSEN: -7.4219929756E-04 -:NPT_NP_HAMIL: -1.4056712231E-05 +:TIO: 1116.01272890409 +:TEN: -3.2407802428E+00 +:KEN: 5.1356373028E-03 +:KENIG: 5.3013030223E-03 +:FEN: -3.2459158801E+00 +:UEN: -3.2450269937E+00 +:TSEN: -8.8888644484E-04 +:NPT_NP_HAMIL: -8.1615849780E-04 +:SNOSE[0]: 1.0089284343E+00 +:SNOSE[1]: 3.3931610398E-05 :R: - 3.5565603918E-01 4.3126351132E-01 2.5188101660E-01 - 3.9136741881E+00 1.5345836961E+01 4.1278877025E+00 - 8.0218477850E+00 1.5174992779E+01 8.8089513281E-02 - 1.1371869711E+01 1.5349001172E+01 3.6166285119E+00 - 1.6479121958E-01 7.9435070157E+00 1.5354929374E+01 - 3.7273082426E+00 7.9432291141E+00 3.8102820813E+00 - 7.2562894144E+00 7.3994023139E+00 1.6774486997E-01 - 1.1548292783E+01 7.8010092962E+00 4.0579607624E+00 - 5.6562267946E-01 1.5155889257E+01 7.7524202594E+00 - 3.6339159948E+00 3.4338443696E-02 1.1220532185E+01 - 7.7078165046E+00 5.4082059005E-02 7.8011892328E+00 - 1.1610581473E+01 1.5161719277E+01 1.1794012733E+01 - 3.1948981770E-01 7.7130190511E+00 7.9102864500E+00 - 4.2676592745E+00 7.9109810352E+00 1.1496814587E+01 - 7.2991788260E+00 8.0443606541E+00 7.5285829337E+00 - 1.1548701075E+01 7.2329007394E+00 1.1503718138E+01 - 1.0597479837E-01 3.9442658678E+00 3.9507117689E+00 - 3.7094588169E+00 3.8766074252E+00 1.8146265166E-02 - 7.8724035520E+00 3.6152344276E+00 3.3690638285E+00 - 1.1362628125E+01 3.8187699357E+00 1.5204339402E+01 - 3.4996308139E-01 1.1430473615E+01 3.9308826386E+00 - 3.5969201065E+00 1.1585608405E+01 5.0220895865E-01 - 7.8716786094E+00 1.1730574810E+01 3.8428335552E+00 - 1.0999304020E+01 1.1523209336E+01 8.8261942696E-02 - 1.5869688363E-01 3.6999048298E+00 1.1220628229E+01 - 3.8150409996E+00 3.6868873965E+00 8.0164812432E+00 - 7.9700403034E+00 3.7680013155E+00 1.1554347970E+01 - 1.1363569706E+01 3.9828089134E+00 7.8578024427E+00 - 3.0844904420E-01 1.1545885597E+01 1.1516732587E+01 - 3.6632426023E+00 1.1233879433E+01 7.8127698069E+00 - 7.8945289714E+00 1.1787307098E+01 1.1739688482E+01 - 1.1653504654E+01 1.1551893054E+01 7.8658369920E+00 + 3.7511919221E-01 3.0242206516E-01 1.7424050226E-01 + 3.8455215345E+00 1.5221383542E+01 4.0128021845E+00 + 7.8673698757E+00 1.5101186899E+01 1.6221642208E-01 + 1.1312665593E+01 1.5226106147E+01 3.6444282490E+00 + 1.1455179643E-01 7.8057735085E+00 1.5229800762E+01 + 3.7343700452E+00 7.7977239499E+00 3.7860664076E+00 + 7.3123563622E+00 7.4185075691E+00 1.1350599895E-01 + 1.1444759875E+01 7.6998989017E+00 3.9611632654E+00 + 5.4110585948E-01 1.5091309000E+01 7.6747390581E+00 + 3.6507029256E+00 2.5120076819E-02 1.1201491319E+01 + 7.6328011266E+00 3.8060247892E-02 7.7928254700E+00 + 1.1479836692E+01 1.5094336869E+01 1.1613765340E+01 + 2.2165603542E-01 7.6367588915E+00 7.7742465779E+00 + 4.1111622655E+00 7.7824065709E+00 1.1408064356E+01 + 7.3448126099E+00 7.8740413350E+00 7.5110169973E+00 + 1.1447927165E+01 7.3102412646E+00 1.1410762802E+01 + 6.5036085290E-02 3.8833179709E+00 3.8865595163E+00 + 3.7237044202E+00 3.8327336510E+00 1.5244591415E+01 + 7.7443089995E+00 3.6557304831E+00 3.5011328263E+00 + 1.1334882605E+01 3.7825876109E+00 1.5124744124E+01 + 3.0979570288E-01 1.1365324161E+01 3.8722211452E+00 + 3.6431960416E+00 1.1470449368E+01 4.8273681102E-01 + 7.7403549374E+00 1.1571378917E+01 3.8325779393E+00 + 1.1093085216E+01 1.1422378254E+01 4.9307342476E-02 + 1.0532545154E-01 3.7076082221E+00 1.1231662975E+01 + 3.8031976080E+00 3.7028913943E+00 7.8335186712E+00 + 7.7996924938E+00 3.7556943801E+00 1.1454313973E+01 + 1.1319393611E+01 3.9093731878E+00 7.7291349552E+00 + 2.9196843017E-01 1.1438401370E+01 1.1440475927E+01 + 3.7144323292E+00 1.1225774035E+01 7.8622776716E+00 + 7.7412017157E+00 1.1609167041E+01 1.1590193986E+01 + 1.1524774329E+01 1.1446690203E+01 7.7280244463E+00 :V: - -9.2479701629E-05 4.8723492619E-04 2.9850139700E-04 - 1.6082431937E-04 -3.4764909374E-05 3.0268923033E-04 - 2.9634566043E-04 -2.1838698287E-04 -3.1518262640E-04 - -1.3506448369E-04 -4.4202500598E-05 -2.1396733644E-04 - 1.9022707338E-04 2.6024194976E-04 -3.3611739036E-05 - -1.6539912942E-04 3.0870672362E-04 -3.4514392062E-05 - -4.5124194659E-04 -3.2191955365E-04 2.0922933210E-04 - 1.5048967072E-05 1.3680256897E-04 2.4617446686E-04 - 2.3764175424E-05 -2.6880590463E-04 1.9159050935E-05 - -1.5882197866E-04 2.5174059951E-05 -2.7113499591E-04 - 3.6153394541E-05 6.4125007250E-05 -2.2952878214E-04 - 1.3812355140E-04 -2.5630304275E-04 3.0479409195E-04 - 3.6765477594E-04 4.1663302499E-05 2.6996074344E-04 - 4.6526457449E-04 2.2722841417E-04 -3.7613081498E-05 - -4.1014129437E-04 3.8644099141E-04 -1.9541286885E-04 - 4.3245133961E-07 -5.5909539613E-04 -2.1251027399E-05 - 1.8322125202E-04 1.0346669798E-04 1.1259907736E-04 - -1.9934566492E-04 4.3028565095E-05 1.0427771335E-04 - 2.4093070563E-04 -2.9634594871E-04 -6.7279131894E-04 - -3.2186117767E-04 3.7061960536E-05 -2.0550685317E-04 - 1.9144845121E-04 -1.4318528615E-04 1.0293168366E-04 - -3.0775536314E-04 5.9636062014E-05 9.3952331010E-05 - 2.5556054811E-04 2.2443044491E-04 -1.2530586908E-04 - -7.9348569087E-04 4.3098358456E-06 1.6376956598E-04 - 2.1016420337E-04 -1.5045196260E-04 -4.5857012392E-04 - -1.0681246780E-04 -1.9202840416E-04 4.6695811690E-04 - 4.3396355665E-04 -7.8852396498E-05 -9.5677528842E-06 - -2.2275582524E-04 1.4714036920E-04 2.6619143670E-04 - 7.5935043864E-05 4.1498595765E-05 -1.2215922704E-04 - -3.8736586086E-04 -3.4532060280E-04 -4.7420642363E-04 - 3.7414748597E-04 3.0443625538E-04 1.7128392031E-04 - 1.0434873927E-04 1.6235522778E-05 2.9957215173E-04 + -8.4627084338E-05 5.2262039645E-04 3.0771307956E-04 + 1.1027859574E-04 -3.7558549926E-05 3.3940727675E-04 + 3.8841756084E-04 -2.4753553678E-04 -2.8621716752E-04 + -1.8508507665E-04 -3.8933214052E-05 -2.6369599286E-04 + 2.0277471810E-04 2.9710917459E-04 -3.2827591454E-05 + -1.5043650913E-04 3.1120409494E-04 -3.8385883205E-05 + -5.1352946159E-04 -3.5100255351E-04 2.1339592919E-04 + 1.2952637683E-05 1.3298501831E-04 2.5528736247E-04 + 1.4362621118E-04 -2.7182465695E-04 6.5392149750E-05 + -2.3361167604E-04 4.4509832320E-05 -3.6378484170E-04 + 2.6279456891E-05 6.3911317717E-05 -2.4583762596E-04 + 1.0263817268E-04 -2.6353807953E-04 3.2269974651E-04 + 3.9601235098E-04 3.3449983056E-05 2.7210996904E-04 + 5.0324623542E-04 2.5869508448E-04 -5.0970468609E-05 + -4.7111417897E-04 4.2505018014E-04 -1.9221726786E-04 + 7.8320002656E-06 -5.6933535715E-04 -3.4120862405E-05 + 1.3967613510E-04 1.1350949850E-04 1.2957765652E-04 + -1.7375982276E-04 3.9421900453E-05 5.4503005942E-05 + 2.3822501697E-04 -2.8332008547E-04 -6.2270006974E-04 + -2.4656845111E-04 -1.3535532481E-05 -2.1804763831E-04 + 1.0538791293E-04 -1.3327137894E-04 9.5376346859E-05 + -3.1612011608E-04 5.6953420753E-05 2.8257891198E-05 + 2.4813573992E-04 2.3731702223E-04 -5.6824208809E-05 + -7.2340389527E-04 8.2651961367E-08 1.3938223298E-04 + 2.0474002797E-04 -1.7143642924E-04 -4.1171948243E-04 + -6.1329436392E-05 -1.9587700810E-04 4.3905689702E-04 + 3.7682990712E-04 -8.7352427284E-05 9.6535238359E-06 + -2.1570773921E-04 1.6730530546E-04 2.1807797703E-04 + 3.3240927514E-05 1.7647908458E-05 -6.6375200440E-05 + -2.8009513807E-04 -3.7519917261E-04 -4.6948710341E-04 + 3.0377665765E-04 3.0865578061E-04 2.1573835965E-04 + 1.2136298130E-04 2.1463754298E-05 2.5810968759E-04 :F: - -6.2328786378E-04 -6.1995517366E-03 -1.4193657085E-03 - 1.0818499382E-02 -6.3651863490E-05 -7.0184299279E-03 - -2.2014238043E-02 7.8069896408E-03 -6.9551267067E-03 - 1.1082634586E-02 -1.2192251282E-03 1.0957170335E-02 - -2.2382451533E-03 -6.6365052581E-03 -4.7664534796E-04 - -3.4485570231E-03 3.9510001212E-04 -3.1786945108E-04 - 1.1514000670E-02 5.3012270353E-03 -1.6881226676E-03 - 1.3957288071E-03 1.7922071872E-03 5.2998930595E-04 - -2.5865311614E-02 -1.0596560201E-03 -1.0711708024E-02 - 1.6452096124E-02 -5.9061551216E-03 2.1167879032E-02 - 1.9636881386E-03 1.4247160456E-03 4.1421808004E-03 - 9.5766010575E-03 2.1396066963E-04 -4.1121611131E-03 - -7.3046987819E-03 1.2128751656E-03 1.9019181528E-04 - -5.3494809177E-03 -5.3812479273E-03 4.2279961599E-03 - 1.3252322864E-02 -7.6960635051E-03 -2.8482667616E-03 - -1.2557780143E-05 1.7333603985E-03 2.9407484556E-03 - 1.1669062128E-02 -1.0298360895E-03 -4.1187903878E-03 - -7.2766547320E-03 1.4579827147E-03 1.0410381237E-02 - 8.1059599079E-04 -4.9558121029E-03 -1.2044902733E-02 - -1.8437225746E-02 1.1632487736E-02 2.4879755080E-03 - 1.8153295738E-02 -2.9371529516E-03 2.3771129330E-03 - 1.6251435220E-03 1.2961593532E-03 1.4769783310E-02 - 2.7952726282E-04 -2.5796086681E-03 -1.3810899074E-02 - -1.3487460614E-02 -1.6851784482E-03 4.8160114064E-03 - -3.6863094883E-05 4.1760786852E-03 -1.0923193842E-02 - -9.5815353233E-03 7.8675263801E-04 4.1389188977E-03 - 1.3306942867E-02 3.3732170654E-04 -3.7083963063E-03 - -2.5939100168E-03 -4.8165167091E-03 1.1272275016E-02 - 9.1852884811E-03 6.5409361105E-03 -1.1557998895E-02 - -2.5220884217E-02 7.8165845929E-03 -2.4567590143E-03 - 1.4065593785E-02 2.1736547873E-04 -8.9277225182E-03 - -1.6601104830E-03 -1.9759436408E-03 8.6677442658E-03 -:LATVEC_SCALE: 1.5380361546E+01 1.5380361546E+01 1.5380361546E+01 + -2.7169504003E-03 -4.6843540266E-03 -1.1479518254E-03 + 1.0485612953E-02 6.4372007168E-04 -5.2281457794E-03 + -1.3617115066E-02 3.1857842282E-03 -6.3203885044E-03 + 8.0075210432E-03 -1.1718865976E-03 8.0068323456E-03 + -1.4556018599E-03 -6.1409179384E-03 -4.1370442972E-04 + -3.2028401062E-03 1.1558523552E-03 1.3305956841E-03 + 9.8877529238E-03 4.0452391451E-03 7.5911774053E-04 + -6.7905056597E-05 6.6000593784E-04 -1.5184711401E-03 + -2.1090514088E-02 3.7967505484E-04 -7.6185395590E-03 + 1.2534234983E-02 -2.1977442088E-03 1.4151686193E-02 + 1.5254971268E-03 -2.6146509976E-04 1.4482199116E-03 + 5.8747973182E-03 6.8038754792E-04 -9.3129766745E-04 + -2.2508383460E-03 2.4240984168E-03 5.6905119001E-04 + -6.3168829813E-03 -5.2373540718E-03 9.9097814629E-04 + 8.0175640033E-03 -5.3103265251E-03 -3.4347358642E-04 + -2.0496606421E-03 -1.2585431973E-03 2.3905753356E-03 + 8.2430474877E-03 -2.4751434726E-03 -1.9035287232E-03 + -4.7134510980E-03 4.2755812184E-04 1.1153604908E-02 + 2.2086246740E-03 -2.8983397189E-03 -1.4133113442E-02 + -1.6195960294E-02 1.0133886636E-02 1.1445904936E-03 + 2.0653477950E-02 -2.7408120351E-03 1.2260798949E-03 + -6.4575064459E-04 -1.9530061346E-04 1.5107675837E-02 + 4.5140441732E-03 -1.3908210113E-03 -1.6696442030E-02 + -2.1451179141E-02 3.6221006374E-03 6.4314961799E-03 + 3.0048953177E-03 3.5362588338E-03 -1.1911285456E-02 + -1.0672475255E-02 -8.9933290289E-04 1.0026997251E-02 + 1.3715462109E-02 2.2890635894E-03 -4.2578677555E-03 + -1.8165758259E-03 -2.3744675450E-03 1.0157917098E-02 + 1.0219982822E-02 4.0262259207E-03 -1.3669648861E-02 + -2.4333060704E-02 2.0811337979E-03 -1.5189739372E-03 + 1.8330948709E-02 5.6122480948E-04 -8.7964059480E-03 + -4.6267020849E-03 -6.1540613986E-04 1.1513820434E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5443945452E+03 +:LATVEC_SCALE: + 1.5246869618E+01 1.5246869618E+01 1.5246869618E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0751799078E+00 -2.7569744791E-02 4.4273640237E-02 - -2.7569744791E-02 -6.8752244704E-01 -1.6596404724E-01 - 4.4273640237E-02 -1.6596404724E-01 -8.9978240195E-01 + 1.0562054543E+00 2.8273213420E-03 7.4343655788E-04 + 2.8273213420E-03 7.8344805200E-01 1.7244866214E-01 + 7.4343655788E-04 1.7244866214E-01 8.8863265974E-01 :STRESS: - -1.9430353677E+00 -4.2641920691E-01 1.6016441300E+00 - -4.2641920691E-01 1.3251869072E+00 4.0916690282E-02 - 1.6016441300E+00 4.0916690282E-02 -5.8577730739E-01 -:PRESIO: 8.8749491894E-01 -:PRES: 4.0120858928E-01 -:PRESIG: 9.2023149673E-01 + -2.9715680298E+00 -3.2756987820E-01 1.2706404083E+00 + -3.2756987820E-01 1.4053184718E+00 4.0630912956E-02 + 1.2706404083E+00 4.0630912956E-02 -2.1024529172E+00 +:CONSTRESS: + 3.8229581003E+00 6.4978060985E-01 -2.4969334766E+00 + 6.4978060985E-01 -5.6362174052E+00 2.6290836133E-01 + -2.4969334766E+00 2.6290836133E-01 1.8132593048E+00 +:TOTSTRESS: + 2.0481538378E-01 -3.1938341031E-01 1.2270365049E+00 + -3.1938341031E-01 5.0143469854E+00 -1.3109061215E-01 + 1.2270365049E+00 -1.3109061215E-01 1.1778262722E+00 +:PRESIO: 9.0942872202E-01 +:PRES: 1.2229008251E+00 +:CONPRES: 1.1430234607E-13 +:TOTPRES: 2.1323295471E+00 +:PRESIG: 9.3876513241E-01 :MIND: -Al - Al: 4.8686254007E+00 -Si - Si: 4.7246798759E+00 -Al - Si: 4.7117690927E+00 -:MDSTEP: 34 -:MDTM: 1.31 +Al - Al: 4.7053396199E+00 +Si - Si: 4.7551249383E+00 +Al - Si: 4.8690124025E+00 + + +:MDSTEP: 24 +:MDTM: 5.61 :TWIST: 0 :TEL: 1120 -:TIO: 1122.16171116726 -:TEN: -3.2410567012E+00 -:KEN: 5.1639335237E-03 -:KENIG: 5.3305120245E-03 -:FEN: -3.2462206347E+00 -:UEN: -3.2454855917E+00 -:TSEN: -7.3504298517E-04 -:NPT_NP_HAMIL: -1.6394731729E-05 +:TIO: 1116.65211485314 +:TEN: -3.2408151416E+00 +:KEN: 5.1385796119E-03 +:KENIG: 5.3043402445E-03 +:FEN: -3.2459537212E+00 +:UEN: -3.2450840953E+00 +:TSEN: -8.6962586997E-04 +:NPT_NP_HAMIL: -8.1526566761E-04 +:SNOSE[0]: 1.0094401634E+00 +:SNOSE[1]: 3.2578169989E-05 :R: - 3.5379646347E-01 4.4379047327E-01 2.5957006800E-01 - 3.9226296870E+00 1.5363936410E+01 4.1403998074E+00 - 8.0388267931E+00 1.5188430123E+01 8.0302608459E-02 - 1.1382713150E+01 1.5366856270E+01 3.6159330123E+00 - 1.6967986578E-01 7.9596868765E+00 1.5373063469E+01 - 3.7277728097E+00 7.9606972360E+00 3.8141310409E+00 - 7.2542194707E+00 7.4006356175E+00 1.7311483228E-01 - 1.1562952330E+01 7.8140601132E+00 4.0690805930E+00 - 5.6658715902E-01 1.5167943048E+01 7.7623401120E+00 - 3.6346767752E+00 3.4930778840E-02 1.1227943411E+01 - 7.7182606678E+00 5.5755422397E-02 7.8051935475E+00 - 1.1628469453E+01 1.5174105951E+01 1.1816085690E+01 - 3.2890218883E-01 7.7235967726E+00 7.9267513513E+00 - 4.2843928422E+00 7.9263184599E+00 1.1510141180E+01 - 7.2982018916E+00 8.0637785520E+00 7.5330083095E+00 - 1.1562981396E+01 7.2280075515E+00 1.1517442557E+01 - 1.1078523866E-01 3.9516905569E+00 3.9583336033E+00 - 3.7090160229E+00 3.8824809859E+00 2.0877198545E-02 - 7.8881097612E+00 3.6122998254E+00 3.3564132880E+00 - 1.1368472342E+01 3.8245463399E+00 1.5218064438E+01 - 3.5535666835E-01 1.1441014533E+01 3.9383184329E+00 - 3.5937591972E+00 1.1601416852E+01 5.0533452032E-01 - 7.8877400114E+00 1.1750598739E+01 3.8443115061E+00 - 1.0993073935E+01 1.1537534152E+01 9.2486304998E-02 - 1.6409947860E-01 3.7007990813E+00 1.1223000139E+01 - 3.8169935645E+00 3.6866947958E+00 8.0380054002E+00 - 7.9907996695E+00 3.7707075515E+00 1.1568343148E+01 - 1.1372060667E+01 3.9913178140E+00 7.8742420430E+00 - 3.1082176713E-01 1.1561258553E+01 1.1527797536E+01 - 3.6578689827E+00 1.1239298496E+01 7.8106451427E+00 - 7.9137221609E+00 1.1809416894E+01 1.1758330730E+01 - 1.1670469292E+01 1.1566545288E+01 7.8830822831E+00 + 3.7348627459E-01 3.1576108881E-01 1.8209950642E-01 + 3.8533019241E+00 1.5240152802E+01 4.0263900702E+00 + 7.8871103467E+00 1.5114602670E+01 1.5527981849E-01 + 1.1322759553E+01 1.5244836016E+01 3.6426468615E+00 + 1.1972594632E-01 7.8232138347E+00 1.5248691767E+01 + 3.7354471670E+00 7.8155495325E+00 3.7900211018E+00 + 7.3091298568E+00 7.4194174961E+00 1.1895639393E-01 + 1.1459891615E+01 7.7131694936E+00 3.9726188029E+00 + 5.4524037311E-01 1.5104091304E+01 7.6862468828E+00 + 3.6497050181E+00 2.6244030726E-02 1.1207042653E+01 + 7.6433407411E+00 3.9694822304E-02 7.7968148483E+00 + 1.1497277982E+01 1.5107330735E+01 1.1636801597E+01 + 2.3176202035E-01 7.6474873028E+00 7.7910673729E+00 + 4.1289388452E+00 7.7988684698E+00 1.1421567988E+01 + 7.3426695940E+00 7.8947520620E+00 7.5159618990E+00 + 1.1462923447E+01 7.3055565359E+00 1.1424697076E+01 + 6.8638078618E-02 3.8911469550E+00 3.8947951162E+00 + 3.7241803082E+00 3.8386749936E+00 1.5265739717E+01 + 7.7602593904E+00 3.6534088752E+00 3.4901165561E+00 + 1.1343331084E+01 3.7872074805E+00 1.5138909521E+01 + 3.1293769176E-01 1.1376706208E+01 3.8796077756E+00 + 3.6400573177E+00 1.1486706170E+01 4.8415405445E-01 + 7.7565601688E+00 1.1592237681E+01 3.8360262226E+00 + 1.1089349052E+01 1.1437183673E+01 5.2870786553E-02 + 1.1056365104E-01 3.7081705963E+00 1.1235902848E+01 + 3.8065322390E+00 3.7028141081E+00 7.8546183193E+00 + 7.8192254199E+00 3.7583993383E+00 1.1469350971E+01 + 1.1328674833E+01 3.9185722790E+00 7.7446132636E+00 + 2.9323313309E-01 1.1453666112E+01 1.1453550561E+01 + 3.7121378273E+00 1.1230997279E+01 7.8607853653E+00 + 7.7588727550E+00 1.1631857835E+01 1.1610496740E+01 + 1.1542674105E+01 1.1462032501E+01 7.7445034862E+00 :V: - -9.2575558038E-05 4.8296851857E-04 2.9708444489E-04 - 1.6588883952E-04 -3.4715081389E-05 2.9844532595E-04 - 2.8457175753E-04 -2.1394481411E-04 -3.1793990909E-04 - -1.2917040106E-04 -4.4711862700E-05 -2.0795060365E-04 - 1.8865304389E-04 2.5629014711E-04 -3.3772418162E-05 - -1.6674479323E-04 3.0817866664E-04 -3.4593059997E-05 - -4.4438639218E-04 -3.1849435871E-04 2.0788734858E-04 - 1.5715776199E-05 1.3738219341E-04 2.4586150898E-04 - 1.0694447576E-05 -2.6870615584E-04 1.3724492789E-05 - -1.5017038867E-04 2.2143187316E-05 -2.5984628509E-04 - 3.7056274475E-05 6.4690851985E-05 -2.2690427826E-04 - 1.4261667619E-04 -2.5559192909E-04 3.0200748084E-04 - 3.6311387877E-04 4.2175448215E-05 2.6942081665E-04 - 4.6147759722E-04 2.2398590692E-04 -3.5397263917E-05 - -4.0250789806E-04 3.8165895255E-04 -1.9638583790E-04 - 4.2511486418E-07 -5.5690689662E-04 -1.9721395028E-05 - 1.8843031082E-04 1.0272529715E-04 1.1034307287E-04 - -2.0239360991E-04 4.3631997031E-05 1.0906423768E-04 - 2.4075525345E-04 -2.9804368675E-04 -6.7702936046E-04 - -3.3001532404E-04 4.2597470657E-05 -2.0382038218E-04 - 1.9977241004E-04 -1.4426788387E-04 1.0383835257E-04 - -3.0624521466E-04 6.0122171575E-05 1.0087036168E-04 - 2.5509394853E-04 2.2265512602E-04 -1.3168658430E-04 - -7.9813684528E-04 3.4851270968E-06 1.6571187827E-04 - 2.0965155595E-04 -1.4807914264E-04 -4.6277034841E-04 - -1.1119238652E-04 -1.9119598466E-04 4.6785929072E-04 - 4.3937394493E-04 -7.8503689009E-05 -1.1337745744E-05 - -2.2348516247E-04 1.4446577912E-04 2.7101334905E-04 - 8.0196130050E-05 4.4562566885E-05 -1.2745837120E-04 - -3.9864478053E-04 -3.4072926310E-04 -4.7427742918E-04 - 3.8006541799E-04 3.0382453155E-04 1.6656525931E-04 - 1.0330060723E-04 1.5242188567E-05 3.0305652285E-04 + -8.5770046891E-05 5.1927530974E-04 3.0656698267E-04 + 1.1538871845E-04 -3.7194101492E-05 3.3611999184E-04 + 3.8067447847E-04 -2.4541766368E-04 -2.8890391656E-04 + -1.8064582377E-04 -3.9465124572E-05 -2.5911960199E-04 + 2.0165256253E-04 2.9346904688E-04 -3.2973651354E-05 + -1.5180273001E-04 3.1124854115E-04 -3.7680169803E-05 + -5.0758451452E-04 -3.4830102329E-04 2.1334099176E-04 + 1.2930023479E-05 1.3311566628E-04 2.5411001240E-04 + 1.3262897958E-04 -2.7118105018E-04 6.1351888508E-05 + -2.2678060235E-04 4.3238241539E-05 -3.5583761676E-04 + 2.6993571271E-05 6.3711532620E-05 -2.4458994311E-04 + 1.0548952176E-04 -2.6274998394E-04 3.2158068392E-04 + 3.9406159381E-04 3.4614934064E-05 2.7189910501E-04 + 4.9917502348E-04 2.5557936501E-04 -5.0306117159E-05 + -4.6610898167E-04 4.2155725865E-04 -1.9211298856E-04 + 6.8332532933E-06 -5.6890805832E-04 -3.2842201555E-05 + 1.4352407396E-04 1.1214122459E-04 1.2837597485E-04 + -1.7578399473E-04 3.9578403187E-05 5.9796015966E-05 + 2.3880318836E-04 -2.8428164574E-04 -6.2839866488E-04 + -2.5404642384E-04 -8.5422488168E-06 -2.1708685453E-04 + 1.1520652277E-04 -1.3439030029E-04 9.5853264246E-05 + -3.1580723014E-04 5.6785628503E-05 3.5548169300E-05 + 2.4976513293E-04 2.3619688636E-04 -6.4757658309E-05 + -7.3236751295E-04 1.7594232471E-06 1.4217592052E-04 + 2.0576814656E-04 -1.6939767507E-04 -4.1676640932E-04 + -6.6391309153E-05 -1.9595537276E-04 4.4299514412E-04 + 3.8282205816E-04 -8.6119316599E-05 7.5900159855E-06 + -2.1621511649E-04 1.6580743701E-04 2.2269313272E-04 + 3.8098087776E-05 1.9633562280E-05 -7.2838527615E-05 + -2.9145143202E-04 -3.7340956617E-04 -4.6944256813E-04 + 3.1205386705E-04 3.0839647036E-04 2.1113632322E-04 + 1.1898976698E-04 2.1093094028E-05 2.6315529996E-04 :F: - -4.6257689099E-04 -6.2033462146E-03 -1.4654276208E-03 - 1.0736990463E-02 -1.2903535063E-04 -7.1000840506E-03 - -2.2766994111E-02 8.4006346099E-03 -6.9221390746E-03 - 1.1249341972E-02 -1.1862650210E-03 1.1171873013E-02 - -2.2321547937E-03 -6.5941055882E-03 -5.2753967922E-04 - -3.3524339717E-03 2.3817815577E-04 -5.3079777709E-04 - 1.1508869683E-02 5.3213097705E-03 -1.9640905198E-03 - 1.5658354899E-03 1.8789906556E-03 8.4273810623E-04 - -2.6037319091E-02 -1.2186710657E-03 -1.0851188754E-02 - 1.6668266842E-02 -6.2596651468E-03 2.1682185541E-02 - 1.9993416887E-03 1.6175469894E-03 4.3499965413E-03 - 9.9504553366E-03 1.6602944311E-04 -4.3729152096E-03 - -7.8244041377E-03 9.6805124770E-04 1.6699996800E-04 - -5.1612175000E-03 -5.2586079273E-03 4.5251743108E-03 - 1.3589168263E-02 -7.8416295538E-03 -3.1456518833E-03 - 2.7459094439E-04 2.0768230235E-03 3.0034614387E-03 - 1.1905873835E-02 -8.9079711357E-04 -4.3053806828E-03 - -7.5181144078E-03 1.5632662335E-03 1.0270153955E-02 - 8.6654003358E-04 -5.1172788840E-03 -1.1861905714E-02 - -1.8579405742E-02 1.1631227930E-02 2.6837276414E-03 - 1.7720278382E-02 -2.8930660841E-03 2.3796393187E-03 - 1.7572348653E-03 1.4295274845E-03 1.4703894388E-02 - -6.3022982525E-05 -2.6863068238E-03 -1.3456542066E-02 - -1.2557674130E-02 -2.2961039494E-03 4.7375624402E-03 - -3.8157345427E-04 4.1817332455E-03 -1.0718071798E-02 - -9.4164009022E-03 1.0159935618E-03 3.5121725302E-03 - 1.3119023043E-02 5.3089749772E-05 -3.6279946800E-03 - -2.6795765982E-03 -5.0160571515E-03 1.1083561788E-02 - 9.1771396864E-03 6.7223923014E-03 -1.1365846058E-02 - -2.5148261563E-02 8.3268354705E-03 -2.2996321657E-03 - 1.3467028173E-02 1.3710387090E-04 -9.0200395197E-03 - -1.3748484246E-03 -2.1377978685E-03 8.4221062733E-03 -:LATVEC_SCALE: 1.5399365773E+01 1.5399365773E+01 1.5399365773E+01 + -2.4242482459E-03 -4.8617829136E-03 -1.2042378242E-03 + 1.0585131047E-02 5.3482327259E-04 -5.3966287808E-03 + -1.4343540185E-02 3.4531056130E-03 -6.3874669785E-03 + 8.2914222052E-03 -1.2173387188E-03 8.2752162497E-03 + -1.5507367378E-03 -6.1864879347E-03 -4.0043427172E-04 + -3.2940374255E-03 1.2423492499E-03 1.1966386361E-03 + 1.0042875494E-02 4.1717653633E-03 5.4656462906E-04 + 7.0494561514E-05 8.0789339708E-04 -1.3322858206E-03 + -2.1534717556E-02 2.3440104602E-04 -7.9512062054E-03 + 1.2911964805E-02 -2.5314709368E-03 1.4795208851E-02 + 1.4966704122E-03 -7.5406141891E-05 1.7487361972E-03 + 6.1755178773E-03 5.6633907666E-04 -1.2063902037E-03 + -2.6645312919E-03 2.4387198996E-03 5.3674542010E-04 + -6.2499890683E-03 -5.2827899915E-03 1.2818483197E-03 + 8.4854820545E-03 -5.5191876600E-03 -6.1471543876E-04 + -1.8588975130E-03 -1.1103263571E-03 2.4411304384E-03 + 8.6927331389E-03 -2.3346038277E-03 -2.0982116704E-03 + -4.9407338918E-03 5.1193954612E-04 1.1120110647E-02 + 1.9507651380E-03 -3.1797034075E-03 -1.4038957735E-02 + -1.6532175468E-02 1.0395579819E-02 1.2045068314E-03 + 2.0696327907E-02 -2.8724264361E-03 1.4529453447E-03 + -4.1099954972E-04 -7.4807763563E-05 1.5222793437E-02 + 4.0624079708E-03 -1.4734349974E-03 -1.6503928294E-02 + -2.0959429063E-02 3.3065596978E-03 6.1470077499E-03 + 2.7646389951E-03 3.6129680705E-03 -1.2000271171E-02 + -1.0696950423E-02 -8.8012534312E-04 9.5076356624E-03 + 1.3842073094E-02 2.1566223773E-03 -4.1960533314E-03 + -1.8826906410E-03 -2.5706245622E-03 1.0530419241E-02 + 1.0095044480E-02 4.3086148173E-03 -1.3527685073E-02 + -2.4667935250E-02 2.5241105219E-03 -1.7857982413E-03 + 1.8124953292E-02 6.6110634683E-04 -8.6143002042E-03 + -4.2768901615E-03 -7.5638112240E-04 1.1251063590E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5581726506E+03 +:LATVEC_SCALE: + 1.5266600431E+01 1.5266600431E+01 1.5266600431E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0756274464E+00 -2.9951360609E-02 4.7263323195E-02 - -2.9951360609E-02 -6.7592599302E-01 -1.6447649000E-01 - 4.7263323195E-02 -1.6447649000E-01 -8.9854667852E-01 + 1.0570834172E+00 5.3885135096E-03 -4.6124145912E-03 + 5.3885135096E-03 7.7333595836E-01 1.7156183095E-01 + -4.6124145912E-03 1.7156183095E-01 8.8885924323E-01 :STRESS: - -1.7765350693E+00 -4.4018694450E-01 1.6187140698E+00 - -4.4018694450E-01 1.3709905370E+00 4.2683917959E-02 - 1.6187140698E+00 4.2683917959E-02 -3.9325835863E-01 -:PRESIO: 8.8336670598E-01 -:PRES: 2.6626763029E-01 -:PRESIG: 9.1617155616E-01 + -2.7256978004E+00 -3.3434768449E-01 1.2982908931E+00 + -3.3434768449E-01 1.4588361094E+00 3.9199705645E-02 + 1.2982908931E+00 3.9199705645E-02 -1.7970305016E+00 +:CONSTRESS: + 3.7381003225E+00 6.6782041997E-01 -2.5640271836E+00 + 6.6782041997E-01 -5.3489798224E+00 2.6414364390E-01 + -2.5640271836E+00 2.6414364390E-01 1.6108794998E+00 +:TOTSTRESS: + 4.4680895047E-02 -3.2808422197E-01 1.2611238759E+00 + -3.2808422197E-01 4.6634796713E+00 -1.3178151859E-01 + 1.2611238759E+00 -1.3178151859E-01 1.0750102450E+00 +:PRESIO: 9.0642620626E-01 +:PRES: 1.0212973975E+00 +:CONPRES: -6.6454852364E-17 +:TOTPRES: 1.9277236038E+00 +:PRESIG: 9.3566576130E-01 :MIND: -Al - Al: 4.8697119225E+00 -Si - Si: 4.7221137626E+00 -Al - Si: 4.6964631383E+00 -:MDSTEP: 35 -:MDTM: 1.30 +Al - Al: 4.6978006922E+00 +Si - Si: 4.7550952639E+00 +Al - Si: 4.8653414403E+00 + + +:MDSTEP: 25 +:MDTM: 6.11 :TWIST: 0 :TEL: 1120 -:TIO: 1121.11075880477 -:TEN: -3.2410862937E+00 -:KEN: 5.1590972795E-03 -:KENIG: 5.3255197723E-03 -:FEN: -3.2462453910E+00 -:UEN: -3.2455158447E+00 -:TSEN: -7.2954623872E-04 -:NPT_NP_HAMIL: -1.8409178231E-05 +:TIO: 1117.12496699586 +:TEN: -3.2408487268E+00 +:KEN: 5.1407555701E-03 +:KENIG: 5.3065863950E-03 +:FEN: -3.2459894824E+00 +:UEN: -3.2451381097E+00 +:TSEN: -8.5137264089E-04 +:NPT_NP_HAMIL: -8.1244267483E-04 +:SNOSE[0]: 1.0100628235E+00 +:SNOSE[1]: 3.9573656779E-05 :R: - 3.5193489694E-01 4.5622914354E-01 2.6723412674E-01 - 3.9317304644E+00 1.5382095505E+01 4.1528317202E+00 - 8.0555455117E+00 1.5202037653E+01 7.2437761950E-02 - 1.1393745224E+01 1.5384758073E+01 3.6153967107E+00 - 1.7453639582E-01 7.9758089647E+00 1.5391252240E+01 - 3.7282144519E+00 7.9781916196E+00 3.8179892481E+00 - 7.2523333576E+00 7.4019727446E+00 1.7845554308E-01 - 1.1577676460E+01 7.8271615464E+00 4.0802205669E+00 - 5.6722822767E-01 1.5180048162E+01 7.7721545080E+00 - 3.6356640119E+00 3.5444457144E-02 1.1235676420E+01 - 7.7287591752E+00 5.7447540700E-02 7.8092887637E+00 - 1.1646523759E+01 1.5186560937E+01 1.1838142595E+01 - 3.3820866706E-01 7.7342158398E+00 7.9432424961E+00 - 4.3010667855E+00 7.9416155064E+00 1.1523570455E+01 - 7.2974338703E+00 8.0831202477E+00 7.5374290615E+00 - 1.1577310563E+01 7.2231831459E+00 1.1531250265E+01 - 1.1573415913E-01 3.9591174137E+00 3.9659164420E+00 - 3.7085027915E+00 3.8883874349E+00 2.3728679405E-02 - 7.9038511213E+00 3.6093257070E+00 3.3436510807E+00 - 1.1374146730E+01 3.8304762968E+00 1.5231886759E+01 - 3.6095920381E-01 1.1451569405E+01 3.9457955748E+00 - 3.5906414396E+00 1.1617286478E+01 5.0863597180E-01 - 7.9038250317E+00 1.1770630809E+01 3.8456464280E+00 - 1.0986756970E+01 1.1551876638E+01 9.6763609401E-02 - 1.6949270320E-01 3.7017619112E+00 1.1225299463E+01 - 3.8188509634E+00 3.6865338311E+00 8.0595911709E+00 - 8.0117365317E+00 3.7734312730E+00 1.1582340514E+01 - 1.1380569928E+01 3.9997784325E+00 7.8908386099E+00 - 3.1330380332E-01 1.1576756475E+01 1.1538774631E+01 - 3.6522181631E+00 1.1244870507E+01 7.8085358492E+00 - 7.9330982588E+00 1.1831566855E+01 1.1776906569E+01 - 1.1687460595E+01 1.1581216902E+01 7.9004517943E+00 + 3.7183392577E-01 3.2904056178E-01 1.8994410839E-01 + 3.8613143584E+00 1.5259328718E+01 4.0400114096E+00 + 7.9068728043E+00 1.5128461138E+01 1.4827113330E-01 + 1.1333256561E+01 1.5263950747E+01 3.6410680620E+00 + 1.2488111918E-01 7.8407778089E+00 1.5267977879E+01 + 3.7365829645E+00 7.8335913761E+00 3.7940906280E+00 + 7.3062274987E+00 7.4205787960E+00 1.2441390580E-01 + 1.1475324441E+01 7.7266505985E+00 3.9841583878E+00 + 5.4911767148E-01 1.5117276056E+01 7.6978557590E+00 + 3.6489675305E+00 2.7336387133E-02 1.1213077804E+01 + 7.6540990818E+00 4.1328642377E-02 7.8010337573E+00 + 1.1515096572E+01 1.5120731180E+01 1.1660123464E+01 + 2.4183544599E-01 7.6584462470E+00 7.8080954740E+00 + 4.1467387016E+00 7.8154652036E+00 1.1435387718E+01 + 7.3408315437E+00 7.9155949611E+00 7.5210986659E+00 + 1.1478196808E+01 7.3010569782E+00 1.1438961817E+01 + 7.2344559828E-02 3.8990483400E+00 3.9031058405E+00 + 3.7246967024E+00 3.8447225841E+00 6.8976700587E-04 + 7.7764334733E+00 3.6511485577E+00 3.4790312136E+00 + 1.1351881332E+01 3.7920518261E+00 1.5153489116E+01 + 3.1633539535E-01 1.1388353678E+01 3.8871122993E+00 + 3.6370132722E+00 1.1503262392E+01 4.8576669751E-01 + 7.7730142594E+00 1.1613379407E+01 3.8393773158E+00 + 1.1085661109E+01 1.1452328639E+01 5.6507689178E-02 + 1.1583527078E-01 3.7088759029E+00 1.1240298381E+01 + 3.8098388071E+00 3.7028259004E+00 7.8760323432E+00 + 7.8391247557E+00 3.7612299092E+00 1.1484637997E+01 + 1.1338233221E+01 3.9278409335E+00 7.7604183122E+00 + 2.9462649249E-01 1.1469282653E+01 1.1466763590E+01 + 3.7096476716E+00 1.1236550255E+01 7.8594838737E+00 + 7.7769611049E+00 1.1654857351E+01 1.1630997338E+01 + 1.1560823373E+01 1.1477665846E+01 7.7613173955E+00 :V: - -9.2604573774E-05 4.7878389406E-04 2.9569313740E-04 - 1.7092671737E-04 -3.4703605671E-05 2.9421558720E-04 - 2.7248875180E-04 -2.0924660663E-04 -3.2072343655E-04 - -1.2322527410E-04 -4.5210396403E-05 -2.0187106450E-04 - 1.8711456688E-04 2.5240780738E-04 -3.3963550062E-05 - -1.6806477760E-04 3.0762021836E-04 -3.4784025179E-05 - -4.3761687537E-04 -3.1511559541E-04 2.0644143036E-04 - 1.6469135467E-05 1.3802534824E-04 2.4574444389E-04 - -2.4314249594E-06 -2.6872798415E-04 8.2338189679E-06 - -1.4145216374E-04 1.8944501194E-05 -2.4836359071E-04 - 3.7980809432E-05 6.5362438801E-05 -2.2421588325E-04 - 1.4730998098E-04 -2.5494582170E-04 2.9914225032E-04 - 3.5837731647E-04 4.2569756432E-05 2.6891185676E-04 - 4.5786468772E-04 2.2084670961E-04 -3.3042224947E-05 - -3.9478372141E-04 3.7687290439E-04 -1.9753652662E-04 - 5.6235709171E-07 -5.5463605611E-04 -1.8166605389E-05 - 1.9377137826E-04 1.0206854923E-04 1.0801880391E-04 - -2.0558271539E-04 4.4291711873E-05 1.1378921400E-04 - 2.4064427208E-04 -2.9986160039E-04 -6.8127376292E-04 - -3.3827103004E-04 4.8126741447E-05 -2.0207434494E-04 - 2.0789944280E-04 -1.4534898017E-04 1.0476022223E-04 - -3.0472164569E-04 6.0680936488E-05 1.0775683060E-04 - 2.5450201750E-04 2.2086638653E-04 -1.3790220364E-04 - -8.0245105348E-04 2.3674224513E-06 1.6763748387E-04 - 2.0900564307E-04 -1.4573159281E-04 -4.6693335827E-04 - -1.1549993840E-04 -1.9028398705E-04 4.6852746300E-04 - 4.4474917188E-04 -7.8305236167E-05 -1.3066717542E-05 - -2.2428869130E-04 1.4172283482E-04 2.7577511036E-04 - 8.4456235844E-05 4.7714373511E-05 -1.3267256589E-04 - -4.0992509578E-04 -3.3595377149E-04 -4.7434528176E-04 - 3.8573942372E-04 3.0322209406E-04 1.6183797935E-04 - 1.0240858215E-04 1.4175138433E-05 3.0646109669E-04 + -8.6754490508E-05 5.1578187512E-04 3.0535485982E-04 + 1.2051896650E-04 -3.6879934237E-05 3.3271227774E-04 + 3.7252969903E-04 -2.4312926569E-04 -2.9157933784E-04 + -1.7604938345E-04 -4.0011302833E-05 -2.5438244523E-04 + 2.0046125705E-04 2.8977716101E-04 -3.3108802657E-05 + -1.5318912202E-04 3.1129126050E-04 -3.7042262155E-05 + -5.0151132301E-04 -3.4549792106E-04 2.1314856995E-04 + 1.2976618494E-05 1.3330129289E-04 2.5299924781E-04 + 1.2141666635E-04 -2.7057775200E-04 5.7147698855E-05 + -2.1974516644E-04 4.1794332898E-05 -3.4753578890E-04 + 2.7689010639E-05 6.3599646682E-05 -2.4316194050E-04 + 1.0847429339E-04 -2.6198517858E-04 3.2028163055E-04 + 3.9185137770E-04 3.5776150148E-05 2.7163532423E-04 + 4.9508456052E-04 2.5241653243E-04 -4.9487488824E-05 + -4.6081785513E-04 4.1791025446E-04 -1.9212022334E-04 + 5.9341301184E-06 -5.6832820811E-04 -3.1537146994E-05 + 1.4755822155E-04 1.1083061878E-04 1.2706438795E-04 + -1.7789251567E-04 3.9772066103E-05 6.5051541866E-05 + 2.3923095137E-04 -2.8533800779E-04 -6.3395268205E-04 + -2.6163595150E-04 -3.4369294879E-06 -2.1606971836E-04 + 1.2500112496E-04 -1.3555037628E-04 9.6419172304E-05 + -3.1534319246E-04 5.6668466793E-05 4.2871918625E-05 + 2.5114149708E-04 2.3500625035E-04 -7.2571315119E-05 + -7.4096416917E-04 3.2731970189E-06 1.4481413072E-04 + 2.0664770258E-04 -1.6730478783E-04 -4.2178187959E-04 + -7.1440489181E-05 -1.9599411481E-04 4.4661110855E-04 + 3.8880685230E-04 -8.4945833905E-05 5.5600501744E-06 + -2.1672673312E-04 1.6419524897E-04 2.2743611626E-04 + 4.2882037196E-05 2.1749589381E-05 -7.9209189840E-05 + -3.0290010017E-04 -3.7135749293E-04 -4.6945459439E-04 + 3.2016344379E-04 3.0814193072E-04 2.0659692900E-04 + 1.1677307066E-04 2.0651188826E-05 2.6802877616E-04 :F: - -3.1476706873E-04 -6.1823426610E-03 -1.5099953127E-03 - 1.0636842561E-02 -1.9135095120E-04 -7.1745501338E-03 - -2.3508186583E-02 9.0176848847E-03 -6.8745637804E-03 - 1.1388777929E-02 -1.1481462686E-03 1.1370579709E-02 - -2.2148219260E-03 -6.5431205821E-03 -5.8543855407E-04 - -3.2347398789E-03 5.6099277351E-05 -7.4743689971E-04 - 1.1488327814E-02 5.3240095481E-03 -2.2385663170E-03 - 1.7378061674E-03 1.9630001129E-03 1.1631132542E-03 - -2.6167652278E-02 -1.3717771111E-03 -1.0960677823E-02 - 1.6857655179E-02 -6.6024462684E-03 2.2166248178E-02 - 2.0438085364E-03 1.8064306729E-03 4.5459863926E-03 - 1.0325571320E-02 1.2120272182E-04 -4.6249700502E-03 - -8.3486619460E-03 6.9366924865E-04 1.4946021972E-04 - -4.9729341662E-03 -5.1191414759E-03 4.8073647090E-03 - 1.3895205274E-02 -7.9684170127E-03 -3.4460882613E-03 - 5.7417566362E-04 2.4340754441E-03 3.0720372227E-03 - 1.2130644153E-02 -7.5880349654E-04 -4.4872194288E-03 - -7.7587835891E-03 1.6661117705E-03 1.0128615413E-02 - 9.5658346832E-04 -5.2629495276E-03 -1.1694677932E-02 - -1.8704540505E-02 1.1603598761E-02 2.9013373951E-03 - 1.7249574051E-02 -2.8296526111E-03 2.3636224320E-03 - 1.8786948133E-03 1.5642973750E-03 1.4633816733E-02 - -3.8827968194E-04 -2.7916902296E-03 -1.3090016426E-02 - -1.1620232846E-02 -2.9185104857E-03 4.6754788382E-03 - -7.2672407455E-04 4.1788471882E-03 -1.0507132671E-02 - -9.2490546556E-03 1.2643368914E-03 2.8907482266E-03 - 1.2905997696E-02 -2.4269834723E-04 -3.5485811778E-03 - -2.7638010616E-03 -5.2169806298E-03 1.0852368561E-02 - 9.1863944508E-03 6.8832084708E-03 -1.1186444806E-02 - -2.5035627196E-02 8.8289813822E-03 -2.1000824588E-03 - 1.2845503139E-02 4.3109154291E-05 -9.1325352093E-03 - -1.0927547606E-03 -2.3006352459E-03 8.1881999592E-03 -:LATVEC_SCALE: 1.5418430496E+01 1.5418430496E+01 1.5418430496E+01 + -2.1417827565E-03 -5.0218914286E-03 -1.2555231956E-03 + 1.0664711812E-02 4.2705477022E-04 -5.5518159077E-03 + -1.5066549392E-02 3.7478342805E-03 -6.4489379048E-03 + 8.5682914281E-03 -1.2534526832E-03 8.5410931573E-03 + -1.6311891806E-03 -6.2172966933E-03 -3.8901599293E-04 + -3.3737502977E-03 1.3148335798E-03 1.0466528657E-03 + 1.0170969024E-02 4.2832446670E-03 3.2642149008E-04 + 2.1351793133E-04 9.4999035053E-04 -1.1277890619E-03 + -2.1955199775E-02 8.0258589061E-05 -8.2665522716E-03 + 1.3275449697E-02 -2.8681678411E-03 1.5428908239E-02 + 1.4710062597E-03 1.1983067708E-04 2.0431772370E-03 + 6.4816055502E-03 4.5406689159E-04 -1.4830528642E-03 + -3.0856498571E-03 2.4363206052E-03 5.0201488684E-04 + -6.1580537334E-03 -5.3115594633E-03 1.5815295318E-03 + 8.9417752174E-03 -5.7236679094E-03 -8.8749322297E-04 + -1.6579850248E-03 -9.5234273181E-04 2.4873530545E-03 + 9.1215283019E-03 -2.1853632432E-03 -2.2958389146E-03 + -5.1748440585E-03 6.0419838531E-04 1.1072636067E-02 + 1.7237697983E-03 -3.4547911501E-03 -1.3927484968E-02 + -1.6855132799E-02 1.0630575131E-02 1.2646821742E-03 + 2.0693770389E-02 -2.9938656797E-03 1.6505206170E-03 + -1.9358686045E-04 4.4028390494E-05 1.5321853355E-02 + 3.6193780003E-03 -1.5600158824E-03 -1.6298492689E-02 + -2.0409465486E-02 2.9625611548E-03 5.8892999051E-03 + 2.5128912039E-03 3.6818910783E-03 -1.2050913491E-02 + -1.0695817599E-02 -8.4469382475E-04 8.9709567937E-03 + 1.3943151239E-02 2.0045559093E-03 -4.1309884272E-03 + -1.9576595852E-03 -2.7665860556E-03 1.0844947724E-02 + 9.9760133182E-03 4.5910669378E-03 -1.3376921266E-02 + -2.4963603736E-02 2.9727040357E-03 -2.0121813921E-03 + 1.7874882720E-02 7.4963093070E-04 -8.4561801482E-03 + -3.9324417499E-03 -9.0095177744E-04 1.0987134620E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5722669372E+03 +:LATVEC_SCALE: + 1.5286731398E+01 1.5286731398E+01 1.5286731398E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0765385299E+00 -3.2248546111E-02 4.9987688399E-02 - -3.2248546111E-02 -6.6457955715E-01 -1.6293214850E-01 - 4.9987688399E-02 -1.6293214850E-01 -8.9750267245E-01 + 1.0578296116E+00 7.9634930924E-03 -9.7333550348E-03 + 7.9634930924E-03 7.6299375672E-01 1.7063923502E-01 + -9.7333550348E-03 1.7063923502E-01 8.8887335665E-01 :STRESS: - -1.6153138057E+00 -4.5448804928E-01 1.6331766039E+00 - -4.5448804928E-01 1.4179728655E+00 4.4985256944E-02 - 1.6331766039E+00 4.4985256944E-02 -2.1568166090E-01 -:PRESIO: 8.7954025315E-01 -:PRES: 1.3767420035E-01 -:PRESIG: 9.1192239306E-01 + -2.4833290892E+00 -3.4175038407E-01 1.3246662458E+00 + -3.4175038407E-01 1.5198231432E+00 3.8002610480E-02 + 1.3246662458E+00 3.8002610480E-02 -1.4937954760E+00 +:CONSTRESS: + 3.6613639921E+00 6.8701055984E-01 -2.6280329331E+00 + 6.8701055984E-01 -5.0743676028E+00 2.6494668256E-01 + -2.6280329331E+00 2.6494668256E-01 1.4130036107E+00 +:TOTSTRESS: + -1.2020529131E-01 -3.3729668268E-01 1.2936333322E+00 + -3.3729668268E-01 4.3175382163E+00 -1.3231005803E-01 + 1.2936333322E+00 -1.3231005803E-01 9.6966522193E-01 +:PRESIO: 9.0323224165E-01 +:PRES: 8.1910047397E-01 +:CONPRES: -9.0777328330E-14 +:TOTPRES: 1.7223327156E+00 +:PRESIG: 9.3236876558E-01 :MIND: -Al - Al: 4.8712957395E+00 -Si - Si: 4.7193617820E+00 -Al - Si: 4.6814813677E+00 -:MDSTEP: 36 -:MDTM: 1.33 +Al - Al: 4.6909041940E+00 +Si - Si: 4.7549192924E+00 +Al - Si: 4.8607680218E+00 + + +:MDSTEP: 26 +:MDTM: 8.18 :TWIST: 0 :TEL: 1120 -:TIO: 1120.43192350127 -:TEN: -3.2411121367E+00 -:KEN: 5.1559734335E-03 -:KENIG: 5.3222951571E-03 -:FEN: -3.2462681101E+00 -:UEN: -3.2455424158E+00 -:TSEN: -7.2569432151E-04 -:NPT_NP_HAMIL: -1.9998093811E-05 +:TIO: 1117.03856754189 +:TEN: -3.2408826142E+00 +:KEN: 5.1403579794E-03 +:KENIG: 5.3061759788E-03 +:FEN: -3.2460229721E+00 +:UEN: -3.2451887493E+00 +:TSEN: -8.3422279394E-04 +:NPT_NP_HAMIL: -8.0718554307E-04 +:SNOSE[0]: 1.0109761945E+00 +:SNOSE[1]: 4.9468106027E-05 :R: - 3.5007182683E-01 4.6858166776E-01 2.7487380597E-01 - 3.9409671119E+00 1.5400277813E+01 4.1651747804E+00 - 8.0719779987E+00 1.5215786706E+01 6.4493558963E-02 - 1.1404940558E+01 1.5402671347E+01 3.6150124268E+00 - 1.7936176882E-01 7.9918571222E+00 1.5409459299E+01 - 3.7286250803E+00 7.9956934432E+00 3.8218449953E+00 - 7.2506113593E+00 7.4033947270E+00 1.8376441813E-01 - 1.1592440727E+01 7.8402974144E+00 4.0913767472E+00 - 5.6754322454E-01 1.5192166112E+01 7.7818443391E+00 - 3.6368706619E+00 3.5875295928E-02 1.1243709642E+01 - 7.7392949779E+00 5.9161015360E-02 7.8134579448E+00 - 1.1664723012E+01 1.5199047150E+01 1.1860154858E+01 - 3.4740415281E-01 7.7448552451E+00 7.9597429688E+00 - 4.3176763439E+00 7.9568569975E+00 1.1537079135E+01 - 7.2968592570E+00 8.1023678728E+00 7.5418229186E+00 - 1.1591665642E+01 7.2184120002E+00 1.1545115404E+01 - 1.2082502429E-01 3.9665395200E+00 3.9734496555E+00 - 3.7079065373E+00 3.8943192951E+00 2.6699524879E-02 - 7.9196119308E+00 3.6063002662E+00 3.3307675591E+00 - 1.1379621751E+01 3.8365508115E+00 1.5245772641E+01 - 3.6676525918E-01 1.1462111766E+01 3.9533053810E+00 - 3.5875581754E+00 1.1633192479E+01 5.1211178732E-01 - 7.9199130756E+00 1.1790643983E+01 3.8468331784E+00 - 1.0980334395E+01 1.1566202741E+01 1.0109384014E-01 - 1.7487327765E-01 3.7027838376E+00 1.1227500188E+01 - 3.8206058150E+00 3.6863978394E+00 8.0812152882E+00 - 8.0328323918E+00 3.7761597639E+00 1.1596314289E+01 - 1.1389068939E+01 4.0081800413E+00 7.9075727161E+00 - 3.1589494927E-01 1.1592354829E+01 1.1549638762E+01 - 3.6462808952E+00 1.1250573484E+01 7.8064235145E+00 - 7.9526336864E+00 1.1853730400E+01 1.1795388574E+01 - 1.1704455646E+01 1.1595879362E+01 7.9179262559E+00 + 3.7016497667E-01 3.4225531125E-01 1.9777179281E-01 + 3.8695478281E+00 1.5278865008E+01 4.0536509223E+00 + 7.9266233245E+00 1.5142722320E+01 1.4119046550E-01 + 1.1344127299E+01 1.5283404969E+01 3.6396854627E+00 + 1.3001508276E-01 7.8584406696E+00 1.5287614277E+01 + 3.7377660854E+00 7.8518258874E+00 3.7982620492E+00 + 7.3036314015E+00 7.4219724037E+00 1.2987448462E-01 + 1.1491026181E+01 7.7403205836E+00 3.9957717242E+00 + 5.5273049621E-01 1.5130817829E+01 7.7095388032E+00 + 3.6484850905E+00 2.8392686596E-02 1.1219572972E+01 + 7.6650530816E+00 4.2963756212E-02 7.8054638736E+00 + 1.1533261757E+01 1.5134493250E+01 1.1683691649E+01 + 2.5186864906E-01 7.6696128939E+00 7.8253061976E+00 + 4.1645486373E+00 7.8321722662E+00 1.1449493716E+01 + 7.3392844150E+00 7.9365423161E+00 7.5264024951E+00 + 1.1493715839E+01 7.2967254632E+00 1.1453523926E+01 + 7.6159775494E-02 3.9070119374E+00 3.9114772443E+00 + 3.7252405843E+00 3.8508659967E+00 2.3723113279E-03 + 7.7928044925E+00 3.6489366893E+00 3.4678706989E+00 + 1.1360497170E+01 3.7971122137E+00 1.5168439785E+01 + 3.1998716506E-01 1.1400232068E+01 3.8947251809E+00 + 3.6340571411E+00 1.1520085231E+01 4.8757420635E-01 + 7.7896877986E+00 1.1634767732E+01 3.8426227737E+00 + 1.1081998597E+01 1.1467775138E+01 6.0214114571E-02 + 1.2113602726E-01 3.7097147111E+00 1.1244817662E+01 + 3.8131064517E+00 3.7029171108E+00 7.8977290188E+00 + 7.8593667784E+00 3.7641735025E+00 1.1500141906E+01 + 1.1348035323E+01 3.9371644960E+00 7.7765298992E+00 + 2.9614595093E-01 1.1485220377E+01 1.1480083384E+01 + 3.7069488245E+00 1.1242406750E+01 7.8583492939E+00 + 7.7954392690E+00 1.1678130881E+01 1.1651662483E+01 + 1.1579191642E+01 1.1493554504E+01 7.7784388302E+00 :V: - -9.2588022148E-05 4.7476711992E-04 2.9437427476E-04 - 1.7595798894E-04 -3.4734346244E-05 2.9004814620E-04 - 2.6014049547E-04 -2.0431195278E-04 -3.2357781459E-04 - -1.1725963733E-04 -4.5702904809E-05 -1.9576597016E-04 - 1.8564609763E-04 2.4863721420E-04 -3.4194061251E-05 - -1.6937545634E-04 3.0706714298E-04 -3.5094531115E-05 - -4.3100701803E-04 -3.1184016715E-04 2.0492448665E-04 - 1.7312774099E-05 1.3875263646E-04 2.4586553432E-04 - -1.5598857804E-05 -2.6891067753E-04 2.7009761367E-06 - -1.3269921120E-04 1.5585223993E-05 -2.3673641641E-04 - 3.8937829764E-05 6.6148226652E-05 -2.2150386342E-04 - 1.5222919662E-04 -2.5440303723E-04 2.9624888306E-04 - 3.5349761478E-04 4.2838484509E-05 2.6847892425E-04 - 4.5449622560E-04 2.1785254712E-04 -3.0559898415E-05 - -3.8704325505E-04 3.7214965546E-04 -1.9889789876E-04 - 8.5031756183E-07 -5.5236271073E-04 -1.6585902404E-05 - 1.9927150241E-04 1.0150871672E-04 1.0564469068E-04 - -2.0894631762E-04 4.5013733482E-05 1.1847231413E-04 - 2.4065212055E-04 -3.0184007425E-04 -6.8564181691E-04 - -3.4667718256E-04 5.3647216706E-05 -2.0028941538E-04 - 2.1584834845E-04 -1.4644271288E-04 1.0570528706E-04 - -3.0323728508E-04 6.1322750411E-05 1.1463001476E-04 - 2.5383331218E-04 2.1909897001E-04 -1.4397185041E-04 - -8.0655411595E-04 9.5157698628E-07 1.6958172663E-04 - 2.0825924347E-04 -1.4343533991E-04 -4.7113216547E-04 - -1.1975445618E-04 -1.8931298013E-04 4.6904002635E-04 - 4.5014997555E-04 -7.8274628958E-05 -1.4758094781E-05 - -2.2520140520E-04 1.3893212309E-04 2.8050210561E-04 - 8.8739115287E-05 5.0952879561E-05 -1.3783154095E-04 - -4.2125751287E-04 -3.3104928005E-04 -4.7446449055E-04 - 3.9122248416E-04 3.0266993844E-04 1.5711572034E-04 - 1.0168661052E-04 1.3035780007E-05 3.0984173050E-04 + -8.7570444669E-05 5.1206082517E-04 3.0402658742E-04 + 1.2563650699E-04 -3.6609033351E-05 3.2913421976E-04 + 3.6392375448E-04 -2.4061523913E-04 -2.9418846860E-04 + -1.7127105026E-04 -4.0560011769E-05 -2.4944379858E-04 + 1.9917387684E-04 2.8599154519E-04 -3.3228421038E-05 + -1.5456222772E-04 3.1127072885E-04 -3.6473357376E-05 + -4.9523827595E-04 -3.4254181142E-04 2.1277803477E-04 + 1.3092180170E-05 1.3351547587E-04 2.5192024945E-04 + 1.0998508859E-04 -2.6997191946E-04 5.2780523372E-05 + -2.1247751670E-04 4.0170468323E-05 -3.3882795119E-04 + 2.8362324287E-05 6.3568365733E-05 -2.4151550760E-04 + 1.1157473470E-04 -2.6119716713E-04 3.1874706113E-04 + 3.8931124216E-04 3.6918060350E-05 2.7127049489E-04 + 4.9090208441E-04 2.4917252894E-04 -4.8502583675E-05 + -4.5516944232E-04 4.1404056628E-04 -1.9220605737E-04 + 5.1385725260E-06 -5.6749199685E-04 -3.0202840617E-05 + 1.5174071715E-04 1.0956231608E-04 1.2562001216E-04 + -1.8005674898E-04 3.9999299851E-05 7.0249592249E-05 + 2.3948233710E-04 -2.8643541542E-04 -6.3924256787E-04 + -2.6928208974E-04 1.7658388751E-06 -2.1495775897E-04 + 1.3472477108E-04 -1.3672227430E-04 9.7043252149E-05 + -3.1468160185E-04 5.6591268674E-05 5.0211035839E-05 + 2.5222580834E-04 2.3370290951E-04 -8.0243693374E-05 + -7.4903586431E-04 4.6100842788E-06 1.4728367595E-04 + 2.0733801803E-04 -1.6513312817E-04 -4.2667282868E-04 + -7.6451040897E-05 -1.9595128021E-04 4.4981869057E-04 + 3.9470172826E-04 -8.3826734390E-05 3.5650830380E-06 + -2.1720852944E-04 1.6244139758E-04 2.3223708961E-04 + 4.7587335781E-05 2.3990533677E-05 -8.5467355367E-05 + -3.1436516718E-04 -3.6897726290E-04 -4.6942148843E-04 + 3.2802585052E-04 3.0783257341E-04 2.0207431427E-04 + 1.1469036597E-04 2.0133080028E-05 2.7268149929E-04 :F: - -1.7929867611E-04 -6.1365353277E-03 -1.5527019868E-03 - 1.0517934536E-02 -2.5105057301E-04 -7.2432017527E-03 - -2.4236341675E-02 9.6565402307E-03 -6.8119036600E-03 - 1.1498981679E-02 -1.1057114496E-03 1.1551999521E-02 - -2.1855915824E-03 -6.4842793260E-03 -6.4984422980E-04 - -3.0964008493E-03 -1.5208545495E-04 -9.6659751755E-04 - 1.1453970039E-02 5.3080235349E-03 -2.5099274228E-03 - 1.9113711336E-03 2.0456937454E-03 1.4891749500E-03 - -2.6256530505E-02 -1.5173150995E-03 -1.1039797950E-02 - 1.7019702746E-02 -6.9326658682E-03 2.2619431441E-02 - 2.0992310528E-03 1.9909430241E-03 4.7312576714E-03 - 1.0701724448E-02 8.0178302148E-05 -4.8684479225E-03 - -8.8763164066E-03 3.8928049056E-04 1.3838987462E-04 - -4.7875899715E-03 -4.9641147918E-03 5.0720698413E-03 - 1.4169930776E-02 -8.0751297869E-03 -3.7486821662E-03 - 8.8602401217E-04 2.8043148660E-03 3.1477810391E-03 - 1.2346853917E-02 -6.3451636515E-04 -4.6636095542E-03 - -7.9991537687E-03 1.7663856533E-03 9.9881037425E-03 - 1.0784355850E-03 -5.3919713192E-03 -1.1545578502E-02 - -1.8812638215E-02 1.1550015429E-02 3.1399265518E-03 - 1.6742285299E-02 -2.7463706111E-03 2.3291494895E-03 - 1.9892494302E-03 1.7012480034E-03 1.4562170811E-02 - -6.9632146456E-04 -2.8953034539E-03 -1.2712450990E-02 - -1.0679459922E-02 -3.5497577320E-03 4.6301385588E-03 - -1.0718840528E-03 4.1669918911E-03 -1.0293661847E-02 - -9.0818865624E-03 1.5318294839E-03 2.2756258171E-03 - 1.2669574742E-02 -5.4922876291E-04 -3.4715998374E-03 - -2.8468051013E-03 -5.4222490181E-03 1.0583508808E-02 - 9.2129319956E-03 7.0219418234E-03 -1.1022910802E-02 - -2.4882426629E-02 9.3220968716E-03 -1.8590667739E-03 - 1.2204547157E-02 -6.3889485717E-05 -9.2660665335E-03 - -8.1410316687E-04 -2.4633089233E-03 7.9673213314E-03 -:LATVEC_SCALE: 1.5437520185E+01 1.5437520185E+01 1.5437520185E+01 + -1.8697020012E-03 -5.1630138803E-03 -1.3016215201E-03 + 1.0724713182E-02 3.2052178238E-04 -5.6938637321E-03 + -1.5785780379E-02 4.0701494187E-03 -6.5033668053E-03 + 8.8361035115E-03 -1.2808922529E-03 8.8029745141E-03 + -1.6966550945E-03 -6.2344844218E-03 -3.8041291361E-04 + -3.4402946477E-03 1.3726452771E-03 8.8266579609E-04 + 1.0272746634E-02 4.3795216992E-03 9.8791577986E-05 + 3.6054702916E-04 1.0859639007E-03 -9.0572346673E-04 + -2.2349444918E-02 -8.1722732599E-05 -8.5631275542E-03 + 1.3623137102E-02 -3.2066696399E-03 1.6050393392E-02 + 1.4484831232E-03 3.2149666027E-04 2.3300742597E-03 + 6.7921999248E-03 3.4412339477E-04 -1.7600845246E-03 + -3.5129315009E-03 2.4155060799E-03 4.6589905395E-04 + -6.0431827516E-03 -5.3222813919E-03 1.8881421260E-03 + 9.3836485115E-03 -5.9218965112E-03 -1.1619578963E-03 + -1.4479510804E-03 -7.8346001672E-04 2.5294675869E-03 + 9.5285394485E-03 -2.0298988045E-03 -2.4963383770E-03 + -5.4157673719E-03 7.0299620315E-04 1.1010815422E-02 + 1.5303877688E-03 -3.7219678453E-03 -1.3803109593E-02 + -1.7164890445E-02 1.0837924200E-02 1.3298119702E-03 + 2.0646872863E-02 -3.1039912323E-03 1.8210747872E-03 + 7.5780746687E-06 1.6152072884E-04 1.5404077264E-02 + 3.1874122656E-03 -1.6500016336E-03 -1.6079976031E-02 + -1.9808391230E-02 2.5928766948E-03 5.6572713291E-03 + 2.2535328175E-03 3.7433654652E-03 -1.2066380660E-02 + -1.0671905437E-02 -7.9309486479E-04 8.4203191319E-03 + 1.4017504937E-02 1.8338098307E-03 -4.0618532829E-03 + -2.0399948984E-03 -2.9607115915E-03 1.1100766744E-02 + 9.8659130962E-03 4.8707545967E-03 -1.3218675870E-02 + -2.5220358757E-02 3.4246744026E-03 -2.1975665091E-03 + 1.7581468194E-02 8.2500178600E-04 -8.3208575702E-03 + -3.5935379704E-03 -1.0487653021E-03 1.0722371352E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.5866479194E+03 +:LATVEC_SCALE: + 1.5307217350E+01 1.5307217350E+01 1.5307217350E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0782591634E+00 -3.4459397676E-02 5.2478957748E-02 - -3.4459397676E-02 -6.5369309924E-01 -1.6137324514E-01 - 5.2478957748E-02 -1.6137324514E-01 -8.9693979329E-01 + 1.0580882435E+00 1.0537058820E-02 -1.4600164186E-02 + 1.0537058820E-02 7.5218188055E-01 1.6961051303E-01 + -1.4600164186E-02 1.6961051303E-01 8.8835310200E-01 :STRESS: - -1.4594484041E+00 -4.6927289720E-01 1.6450849968E+00 - -4.6927289720E-01 1.4653198272E+00 4.7784701968E-02 - 1.6450849968E+00 4.7784701968E-02 -5.4198855530E-02 -:PRESIO: 8.7629735199E-01 -:PRES: 1.6109144155E-02 -:PRESIG: 9.0799346124E-01 + -2.2453517341E+00 -3.4983456731E-01 1.3494734247E+00 + -3.4983456731E-01 1.5875836305E+00 3.7140293998E-02 + 1.3494734247E+00 3.7140293998E-02 -1.1947359581E+00 +:CONSTRESS: + 3.5922795857E+00 7.0745490053E-01 -2.6884859701E+00 + 7.0745490053E-01 -4.8136275206E+00 2.6501640824E-01 + -2.6884859701E+00 2.6501640824E-01 1.2213479349E+00 +:TOTSTRESS: + -2.8883960807E-01 -3.4708327441E-01 1.3244123812E+00 + -3.4708327441E-01 3.9782257706E+00 -1.3254618921E-01 + 1.3244123812E+00 -1.3254618921E-01 8.6174112519E-01 +:PRESIO: 8.9954107535E-01 +:PRES: 6.1750135388E-01 +:CONPRES: -6.8182678526E-14 +:TOTPRES: 1.5170424292E+00 +:PRESIG: 9.2855852940E-01 :MIND: -Al - Al: 4.8733714740E+00 -Si - Si: 4.7164169629E+00 -Al - Si: 4.6668340045E+00 -:MDSTEP: 37 -:MDTM: 1.29 +Al - Al: 4.6846532661E+00 +Si - Si: 4.7545875058E+00 +Al - Si: 4.8443974927E+00 + + +:MDSTEP: 27 +:MDTM: 5.63 :TWIST: 0 :TEL: 1120 -:TIO: 1120.48220850842 -:TEN: -3.2411328714E+00 -:KEN: 5.1562048336E-03 -:KENIG: 5.3225340218E-03 -:FEN: -3.2462890762E+00 -:UEN: -3.2455656297E+00 -:TSEN: -7.2344652570E-04 -:NPT_NP_HAMIL: -2.1261011563E-05 +:TIO: 1116.4636450412 +:TEN: -3.2409163941E+00 +:KEN: 5.1377123166E-03 +:KENIG: 5.3034449719E-03 +:FEN: -3.2460541064E+00 +:UEN: -3.2452358279E+00 +:TSEN: -8.1827843695E-04 +:NPT_NP_HAMIL: -8.0128270456E-04 +:SNOSE[0]: 1.0121512683E+00 +:SNOSE[1]: 5.4486617910E-05 :R: - 3.4820754709E-01 4.8085080381E-01 2.8248994157E-01 - 3.9503304221E+00 1.5418447945E+01 4.1774208271E+00 - 8.0880990628E+00 1.5229649818E+01 5.6468532558E-02 - 1.1416274162E+01 1.5420561909E+01 3.6147729403E+00 - 1.8415721152E-01 8.0078159482E+00 1.5427649186E+01 - 3.7289969869E+00 8.0131842932E+00 3.8256867746E+00 - 7.2490338587E+00 7.4048826877E+00 1.8903904647E-01 - 1.1607221495E+01 7.8534521431E+00 4.1025457029E+00 - 5.6752989507E-01 1.5204259343E+01 7.7913913418E+00 - 3.6382895880E+00 3.6219249639E-02 1.1252021839E+01 - 7.7498517177E+00 6.0898447461E-02 7.8176844248E+00 - 1.1683046777E+01 1.5211528413E+01 1.1882094956E+01 - 3.5648371405E-01 7.7554941585E+00 7.9762366408E+00 - 4.3342172722E+00 7.9720285945E+00 1.1550644502E+01 - 7.2964624680E+00 8.1215045497E+00 7.5461679450E+00 - 1.1606024628E+01 7.2136788934E+00 1.1559012986E+01 - 1.2606139248E-01 3.9739501909E+00 3.9809229917E+00 - 3.7072147550E+00 3.9002693561E+00 2.9788695997E-02 - 7.9353775595E+00 3.6032119191E+00 3.3177525791E+00 - 1.1384868514E+01 3.8427609293E+00 1.5259689515E+01 - 3.7276922332E-01 1.1472616047E+01 3.9608392914E+00 - 3.5845006697E+00 1.1649110902E+01 5.1576060663E-01 - 7.9359844493E+00 1.1810612160E+01 3.8478668416E+00 - 1.0973787670E+01 1.1580479065E+01 1.0547732283E-01 - 1.8023806675E-01 3.7038554489E+00 1.1229576724E+01 - 3.8222508655E+00 3.6862805176E+00 8.1028554236E+00 - 8.0540693663E+00 3.7788803835E+00 1.1610239419E+01 - 1.1397529770E+01 4.0165121931E+00 7.9244252501E+00 - 3.1859533463E-01 1.1608029662E+01 1.1560365257E+01 - 3.6400482614E+00 1.1256385918E+01 7.8042904304E+00 - 7.9723054878E+00 1.1875881783E+01 1.1813749914E+01 - 1.1721432326E+01 1.1610504908E+01 7.9354873280E+00 + 3.6848235834E-01 3.5539946830E-01 2.0557954667E-01 + 3.8779913350E+00 1.5298717640E+01 4.0672934443E+00 + 7.9463285057E+00 1.5157349174E+01 1.3403862577E-01 + 1.1355344239E+01 1.5303155666E+01 3.6384935919E+00 + 1.3512542771E-01 7.8761784015E+00 1.5307558330E+01 + 3.7389861882E+00 7.8702297833E+00 3.8025228592E+00 + 7.3013253102E+00 7.4235807662E+00 1.3533358856E-01 + 1.1506966311E+01 7.7541585670E+00 4.0074488101E+00 + 5.5607187287E-01 1.5144673766E+01 7.7212703898E+00 + 3.6482530035E+00 2.9408387052E-02 1.1226506389E+01 + 7.6761807350E+00 4.4602171566E-02 7.8100883454E+00 + 1.1551744275E+01 1.5148574672E+01 1.1707467889E+01 + 2.6185317775E-01 7.6809651846E+00 7.8426754151E+00 + 4.1823553925E+00 7.8489660181E+00 1.1463857942E+01 + 7.3380158731E+00 7.9575668243E+00 7.5318500099E+00 + 1.1509450861E+01 7.2925471462E+00 1.1468351918E+01 + 8.0087384065E-02 3.9150279788E+00 3.9198951656E+00 + 3.7257997560E+00 3.8570953477E+00 4.1856343319E-03 + 7.8093467242E+00 3.6467616174E+00 3.4566308640E+00 + 1.1369144779E+01 3.8023803667E+00 1.5183721025E+01 + 3.2389051938E-01 1.1412308902E+01 3.9024369125E+00 + 3.6311830945E+00 1.1537143384E+01 4.8957575444E-01 + 7.8065521060E+00 1.1656367449E+01 3.8457550710E+00 + 1.1078342452E+01 1.1483486452E+01 6.3986134848E-02 + 1.2646114846E-01 3.7106783341E+00 1.1249431673E+01 + 3.8163253171E+00 3.7030791836E+00 7.9196766583E+00 + 7.8799277258E+00 3.7672179938E+00 1.1515831236E+01 + 1.1358049636E+01 3.9465285841E+00 7.7929277157E+00 + 2.9778896908E-01 1.1501450195E+01 1.1493480242E+01 + 3.7040299566E+00 1.1248542885E+01 7.8573602574E+00 + 7.8142796216E+00 1.1701644602E+01 1.1672459886E+01 + 1.1597749779E+01 1.1509664289E+01 7.7958409612E+00 :V: - -9.2523802785E-05 4.7088528415E-04 2.9310132200E-04 - 1.8095997632E-04 -3.4802787741E-05 2.8591734707E-04 - 2.4750385807E-04 -1.9910914087E-04 -3.2646756211E-04 - -1.1127444519E-04 -4.6183350574E-05 -1.8962308825E-04 - 1.8423592089E-04 2.4495761754E-04 -3.4464189754E-05 - -1.7065181775E-04 3.0647819621E-04 -3.5522636709E-05 - -4.2452096729E-04 -3.0864733336E-04 2.0331884455E-04 - 1.8246227100E-05 1.3955108306E-04 2.4620505429E-04 - -2.8792523512E-05 -2.6922591227E-04 -2.8618717895E-06 - -1.2390867204E-04 1.2068744952E-05 -2.2495291664E-04 - 3.9929783155E-05 6.7040255489E-05 -2.1875215675E-04 - 1.5736331297E-04 -2.5393817013E-04 2.9330338347E-04 - 3.4843869935E-04 4.2962999677E-05 2.6810061520E-04 - 4.5132738388E-04 2.1498969367E-04 -2.7955209388E-05 - -3.7926312485E-04 3.6746300026E-04 -2.0045341080E-04 - 1.2949959784E-06 -5.5002911187E-04 -1.4973375524E-05 - 2.0491117336E-04 1.0103242279E-04 1.0321262189E-04 - -2.1246686129E-04 4.5793024493E-05 1.2310587905E-04 - 2.4077220628E-04 -3.0394451981E-04 -6.9008234968E-04 - -3.5519839307E-04 5.9144446386E-05 -1.9843642762E-04 - 2.2358643059E-04 -1.4752677777E-04 1.0665551674E-04 - -3.0176910063E-04 6.2043320979E-05 1.2148246854E-04 - 2.5307295318E-04 2.1733292076E-04 -1.4988063417E-04 - -8.1037395178E-04 -7.6702966690E-07 1.7153836070E-04 - 2.0739326996E-04 -1.4118042748E-04 -4.7532507815E-04 - -1.2394754419E-04 -1.8825614476E-04 4.6935810364E-04 - 4.5552712903E-04 -7.8409681458E-05 -1.6412683166E-05 - -2.2620263296E-04 1.3607755652E-04 2.8515330405E-04 - 9.3047342437E-05 5.4264374514E-05 -1.4293333940E-04 - -4.3259023651E-04 -3.2598778787E-04 -4.7457202680E-04 - 3.9647303049E-04 3.0213399782E-04 1.5237155684E-04 - 1.0112315357E-04 1.1822525169E-05 3.1317852198E-04 + -8.8226144773E-05 5.0814163672E-04 3.0259556079E-04 + 1.3073239020E-04 -3.6381668575E-05 3.2540496304E-04 + 3.5487637997E-04 -2.3787129862E-04 -2.9673553421E-04 + -1.6632474606E-04 -4.1107832624E-05 -2.4431733521E-04 + 1.9780468643E-04 2.8213075971E-04 -3.3335483669E-05 + -1.5591920549E-04 3.1118904014E-04 -3.5981461001E-05 + -4.8879833190E-04 -3.3945374557E-04 2.1223362117E-04 + 1.3278668452E-05 1.3375916811E-04 2.5089004174E-04 + 9.8358561119E-05 -2.6937626820E-04 4.8264681651E-05 + -2.0499759518E-04 3.8368608408E-05 -3.2973724212E-04 + 2.9016314316E-05 6.3622329849E-05 -2.3966395389E-04 + 1.1479458576E-04 -2.6039401020E-04 3.1698872458E-04 + 3.8645310934E-04 3.8031401087E-05 2.7081324529E-04 + 4.8665711367E-04 2.4586707894E-04 -4.7351116234E-05 + -4.4919035488E-04 4.0996788235E-04 -1.9237732262E-04 + 4.4518374513E-06 -5.6641310736E-04 -2.8842565301E-05 + 1.5606293506E-04 1.0834301580E-04 1.2404677771E-04 + -1.8228404775E-04 4.0263632618E-05 7.5382674413E-05 + 2.3958281677E-04 -2.8757782736E-04 -6.4428132905E-04 + -2.7698201872E-04 7.0498258580E-06 -2.1375563082E-04 + 1.4435439747E-04 -1.3790382876E-04 9.7715571337E-05 + -3.1384125157E-04 5.6555418425E-05 5.7554531687E-05 + 2.5303230499E-04 2.3229361771E-04 -8.7767096019E-05 + -7.5657955031E-04 5.7574316923E-06 1.4960015407E-04 + 2.0784204497E-04 -1.6289297876E-04 -4.3143383657E-04 + -8.1412685246E-05 -1.9582484711E-04 4.5262555197E-04 + 4.0050292720E-04 -8.2774033447E-05 1.6085083676E-06 + -2.1767046729E-04 1.6055347009E-04 2.3707180953E-04 + 5.2217702441E-05 2.6353531942E-05 -9.1608867860E-05 + -3.2583126878E-04 -3.6628231106E-04 -4.6933829890E-04 + 3.3562731717E-04 3.0747183509E-04 1.9756684121E-04 + 1.1274357649E-04 1.9538433715E-05 2.7711980361E-04 :F: - -5.5715220087E-05 -6.0658458285E-03 -1.5930282601E-03 - 1.0380496662E-02 -3.0884344141E-04 -7.3067882365E-03 - -2.4949940964E-02 1.0315316814E-02 -6.7337083287E-03 - 1.1578610938E-02 -1.0597729337E-03 1.1715129924E-02 - -2.1430283611E-03 -6.4187982202E-03 -7.2039326577E-04 - -2.9382710338E-03 -3.8701210162E-04 -1.1868554583E-03 - 1.1408158606E-02 5.2723471061E-03 -2.7772600972E-03 - 2.0862838477E-03 2.1285099148E-03 1.8199424499E-03 - -2.6303842661E-02 -1.6536107244E-03 -1.1088117694E-02 - 1.7154286845E-02 -7.2487472806E-03 2.3040302485E-02 - 2.1674690624E-03 2.1710418631E-03 4.9071646821E-03 - 1.1078550650E-02 4.4083913873E-05 -5.1034518658E-03 - -9.4065406959E-03 5.4707340450E-05 1.3465603177E-04 - -4.6084925453E-03 -4.7948419637E-03 5.3167933686E-03 - 1.4413438146E-02 -8.1606051004E-03 -4.0526416720E-03 - 1.2095177394E-03 3.1863041596E-03 3.2310730140E-03 - 1.2558009207E-02 -5.1849731119E-04 -4.8333958238E-03 - -8.2397679778E-03 1.8642401190E-03 9.8503559641E-03 - 1.2288108534E-03 -5.5035216528E-03 -1.1416338724E-02 - -1.8903845976E-02 1.1470896316E-02 3.3973536402E-03 - 1.6199417816E-02 -2.6424008511E-03 2.2760244774E-03 - 2.0881607645E-03 1.8405888473E-03 1.4491452904E-02 - -9.8761820090E-04 -2.9962710696E-03 -1.2324279320E-02 - -9.7395671430E-03 -4.1874267832E-03 4.6010135591E-03 - -1.4178081396E-03 4.1458058555E-03 -1.0080014457E-02 - -8.9161610635E-03 1.8182807277E-03 1.6677918368E-03 - 1.2412288429E-02 -8.6572381887E-04 -3.3984493113E-03 - -2.9290180359E-03 -5.6344737168E-03 1.0282020085E-02 - 9.2564908332E-03 7.1375182250E-03 -1.0878538564E-02 - -2.4688097952E-02 9.8054258595E-03 -1.5776515718E-03 - 1.1547331009E-02 -1.8344520085E-04 -9.4214320839E-03 - -5.3960543894E-04 -2.6252290627E-03 7.7612703132E-03 -:LATVEC_SCALE: 1.5456600346E+01 1.5456600346E+01 1.5456600346E+01 + -1.6091571402E-03 -5.2826268325E-03 -1.3428941620E-03 + 1.0764744023E-02 2.1663606237E-04 -5.8252701028E-03 + -1.6501691194E-02 4.4207280402E-03 -6.5495345397E-03 + 9.0926613884E-03 -1.2995644350E-03 9.0601025625E-03 + -1.7499247395E-03 -6.2381224291E-03 -3.7670003662E-04 + -3.4920698554E-03 1.4129345126E-03 7.0631531031E-04 + 1.0350197613E-02 4.4597391662E-03 -1.3427832161E-04 + 5.1056117039E-04 1.2154925829E-03 -6.6821944259E-04 + -2.2716687783E-02 -2.5027507388E-04 -8.8402445173E-03 + 1.3954070595E-02 -3.5461988273E-03 1.6660019884E-02 + 1.4317139816E-03 5.2764829251E-04 2.6084963430E-03 + 7.1072493990E-03 2.3541781947E-04 -2.0367088333E-03 + -3.9456032916E-03 2.3741499366E-03 4.2888397927E-04 + -5.9077667971E-03 -5.3131383352E-03 2.1989986769E-03 + 9.8092712770E-03 -6.1124873422E-03 -1.4381216739E-03 + -1.2278063161E-03 -6.0278780275E-04 2.5699656422E-03 + 9.9131887763E-03 -1.8703469312E-03 -2.6992950288E-03 + -5.6621242803E-03 8.0537489346E-04 1.0935370586E-02 + 1.3756887796E-03 -3.9783000851E-03 -1.3670774880E-02 + -1.7459760227E-02 1.1019418219E-02 1.4030655337E-03 + 2.0554502057E-02 -3.2012566097E-03 1.9667381736E-03 + 1.9278001725E-04 2.7870221272E-04 1.5469376699E-02 + 2.7695598681E-03 -1.7441285610E-03 -1.5849757945E-02 + -1.9161065968E-02 2.1976584252E-03 5.4489432391E-03 + 1.9862862380E-03 3.7979440052E-03 -1.2048677585E-02 + -1.0630164164E-02 -7.2230632499E-04 7.8594696766E-03 + 1.4064182046E-02 1.6455488158E-03 -3.9878673768E-03 + -2.1280707201E-03 -3.1526527915E-03 1.1296570934E-02 + 9.7668480589E-03 5.1448891856E-03 -1.3053821567E-02 + -2.5439186178E-02 3.8759193718E-03 -2.3403553143E-03 + 1.7247948759E-02 8.8538214799E-04 -8.2075373394E-03 + -3.2603753938E-03 -1.1993913084E-03 1.0457741426E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6012873408E+03 +:LATVEC_SCALE: + 1.5328015285E+01 1.5328015285E+01 1.5328015285E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0805995468E+00 -3.6566377215E-02 5.4747606331E-02 - -3.6566377215E-02 -6.4314444162E-01 -1.5976158444E-01 - 5.4747606331E-02 -1.5976158444E-01 -8.9670264664E-01 + 1.0579410448E+00 1.3095663992E-02 -1.9198845081E-02 + 1.3095663992E-02 7.4098166418E-01 1.6847671260E-01 + -1.9198845081E-02 1.6847671260E-01 8.8734717900E-01 :STRESS: - -1.3090034081E+00 -4.8445137646E-01 1.6545438891E+00 - -4.8445137646E-01 1.5121903728E+00 5.1006960426E-02 - 1.6545438891E+00 5.1006960426E-02 9.0268327681E-02 -:PRESIO: 8.7348221170E-01 -:PRES: -9.7818430819E-02 -:PRESIG: 9.0467563502E-01 + -2.0124409372E+00 -3.5858330867E-01 1.3725230044E+00 + -3.5858330867E-01 1.6613673225E+00 3.6499157365E-02 + 1.3725230044E+00 3.6499157365E-02 -9.0176508422E-01 +:CONSTRESS: + 3.5304507918E+00 7.2923177564E-01 -2.7451382847E+00 + 7.2923177564E-01 -4.5680757794E+00 2.6432560167E-01 + -2.7451382847E+00 2.6432560167E-01 1.0376249876E+00 +:TOTSTRESS: + -4.6006880978E-01 -3.5755280298E-01 1.3534164352E+00 + -3.5755280298E-01 3.6476901211E+00 -1.3234804643E-01 + 1.3534164352E+00 -1.3234804643E-01 7.5148727562E-01 +:PRESIO: 8.9542329599E-01 +:PRES: 4.1761289964E-01 +:CONPRES: 1.0160946927E-13 +:TOTPRES: 1.3130361956E+00 +:PRESIG: 9.2430791844E-01 :MIND: -Al - Al: 4.8759334669E+00 -Si - Si: 4.7132723730E+00 -Al - Si: 4.6525313307E+00 -:MDSTEP: 38 -:MDTM: 1.29 +Al - Al: 4.6790518349E+00 +Si - Si: 4.7540918280E+00 +Al - Si: 4.8282176847E+00 + + +:MDSTEP: 28 +:MDTM: 5.54 :TWIST: 0 :TEL: 1120 -:TIO: 1121.06365849267 -:TEN: -3.2411496066E+00 -:KEN: 5.1588805345E-03 -:KENIG: 5.3252960356E-03 -:FEN: -3.2463084872E+00 -:UEN: -3.2455857551E+00 -:TSEN: -7.2273209812E-04 -:NPT_NP_HAMIL: -2.2373769585E-05 +:TIO: 1115.87191967292 +:TEN: -3.2409479758E+00 +:KEN: 5.1349893307E-03 +:KENIG: 5.3006341478E-03 +:FEN: -3.2460829652E+00 +:UEN: -3.2452793251E+00 +:TSEN: -8.0364004922E-04 +:NPT_NP_HAMIL: -8.0047926355E-04 +:SNOSE[0]: 1.0133774317E+00 +:SNOSE[1]: 5.1007641805E-05 :R: - 3.4634275711E-01 4.9303754279E-01 2.9008211198E-01 - 3.9598115329E+00 1.5436576063E+01 4.1895618363E+00 - 8.1038852299E+00 1.5243606056E+01 4.8362929890E-02 - 1.1427725211E+01 1.5438401195E+01 3.6146730076E+00 - 1.8892330394E-01 8.0236717260E+00 1.5445791887E+01 - 3.7293247935E+00 8.0306467695E+00 3.8295045597E+00 - 7.2475856711E+00 7.4064215573E+00 1.9427616717E-01 - 1.1621999109E+01 7.8666122455E+00 4.1137243359E+00 - 5.6718670638E-01 1.5216296965E+01 7.8007803065E+00 - 3.6399152421E+00 3.6472373586E-02 1.1260596450E+01 - 7.7604157150E+00 6.2662097202E-02 7.8219551905E+00 - 1.1701478003E+01 1.5223975092E+01 1.1903938208E+01 - 3.6544083274E-01 7.7661138733E+00 7.9927089901E+00 - 4.3506846074E+00 7.9871178727E+00 1.1564247762E+01 - 7.2962319191E+00 8.1405147241E+00 7.5504457392E+00 - 1.1620369699E+01 7.2089738573E+00 1.1572922221E+01 - 1.3144589927E-01 3.9813435455E+00 3.9883271568E+00 - 3.7064171884E+00 3.9062315273E+00 3.2994667795E-02 - 7.9511353521E+00 3.6000519489E+00 3.3046001004E+00 - 1.1389863875E+01 3.8490985037E+00 1.5273611297E+01 - 3.7896422125E-01 1.1483061597E+01 3.9683894103E+00 - 3.5814627225E+00 1.1665021591E+01 5.1958075949E-01 - 7.9520212305E+00 1.1830512346E+01 3.8487446080E+00 - 1.0967105811E+01 1.1594676162E+01 1.0991383063E-01 - 1.8558301160E-01 3.7049691939E+00 1.1231509572E+01 - 3.8237807110E+00 3.6861779625E+00 8.1244899645E+00 - 8.0754300442E+00 3.7815820547E+00 1.1624094898E+01 - 1.1405929515E+01 4.0247650902E+00 7.9413781778E+00 - 3.2140501085E-01 1.1623760556E+01 1.1570933852E+01 - 3.6335150171E+00 1.1262291673E+01 7.8021243090E+00 - 7.9920914853E+00 1.1897997818E+01 1.1831966843E+01 - 1.1738372063E+01 1.1625069766E+01 7.9531181773E+00 + 3.6678857465E-01 3.6846887603E-01 2.1336526603E-01 + 3.8866335226E+00 1.5318840869E+01 4.0809244718E+00 + 7.9659552503E+00 1.5172302681E+01 1.2681570809E-01 + 1.1366877963E+01 1.5323158181E+01 3.6374857759E+00 + 1.4021045749E-01 7.8939671562E+00 1.5327765612E+01 + 3.7402322921E+00 7.8887795950E+00 3.8068598827E+00 + 7.2992904260E+00 7.4253843383E+00 1.4078720000E-01 + 1.1523113143E+01 7.7681431274E+00 4.0191801245E+00 + 5.5913552519E-01 1.5158798538E+01 7.7330245014E+00 + 3.6482653031E+00 3.0379063003E-02 1.1233853887E+01 + 7.6874593594E+00 4.6246124618E-02 7.8148886767E+00 + 1.1570513958E+01 1.5162930820E+01 1.1731413589E+01 + 2.7178161209E-01 7.6924800730E+00 7.8601789150E+00 + 4.2001469380E+00 7.8658229594E+00 1.1478451033E+01 + 7.3370112506E+00 7.9786416315E+00 7.5374164662E+00 + 1.1525371110E+01 7.2885049361E+00 1.1483412961E+01 + 8.4131151446E-02 3.9230866434E+00 3.9283453625E+00 + 3.7263610688E+00 3.8634004916E+00 6.1284395405E-03 + 7.8260347482E+00 3.6446106334E+00 3.4453055290E+00 + 1.1377788611E+01 3.8078472443E+00 1.5199290184E+01 + 3.2804268729E-01 1.1424550262E+01 3.9102375337E+00 + 3.6283838243E+00 1.1554404466E+01 4.9177033298E-01 + 7.8235785402E+00 1.1678142720E+01 3.8487662509E+00 + 1.1074670929E+01 1.1499424330E+01 6.7820496355E-02 + 1.3180633599E-01 3.7117571172E+00 1.1254109430E+01 + 3.8194851819E+00 3.7033028428E+00 7.9418438486E+00 + 7.9007837164E+00 3.7703503990E+00 1.1531673375E+01 + 1.1368242764E+01 3.9559188949E+00 7.8095905033E+00 + 2.9955320119E-01 1.1517941759E+01 1.1506923127E+01 + 3.7008790182E+00 1.1254932500E+01 7.8564937422E+00 + 7.8334540735E+00 1.1725364126E+01 1.1693356351E+01 + 1.1616467678E+01 1.1525959812E+01 7.8134968548E+00 :V: - -9.2392668169E-05 4.6702125201E-04 2.9179502926E-04 - 1.8587476253E-04 -3.4898399534E-05 2.8174678755E-04 - 2.3451683722E-04 -1.9357327089E-04 -3.2929600895E-04 - -1.0525367952E-04 -4.6637442350E-05 -1.8339879449E-04 - 1.8284002738E-04 2.4130459204E-04 -3.4767581316E-05 - -1.7183750589E-04 3.0575606495E-04 -3.6059050421E-05 - -4.1804708444E-04 -3.0546191904E-04 2.0157081161E-04 - 1.9265187022E-05 1.4038260013E-04 2.4669772586E-04 - -4.1985813586E-05 -2.6959523636E-04 -8.4393271624E-06 - -1.1505906214E-04 8.3985558350E-06 -2.1296611301E-04 - 4.0952310269E-05 6.8017938494E-05 -2.1590525800E-04 - 1.6267013608E-04 -2.5347908186E-04 2.9022939933E-04 - 3.4310344055E-04 4.2916625700E-05 2.6770714850E-04 - 4.4823071382E-04 2.1220581768E-04 -2.5230341773E-05 - -3.7135408098E-04 3.6272228437E-04 -2.0214886264E-04 - 1.9017069093E-06 -5.4747863732E-04 -1.3320911197E-05 - 2.1063262618E-04 1.0060781488E-04 1.0069725378E-04 - -2.1608668872E-04 4.6615925434E-05 1.2765845111E-04 - 2.4095230930E-04 -3.0608350795E-04 -6.9441688055E-04 - -3.6373060428E-04 6.4590877532E-05 -1.9645180739E-04 - 2.3103701201E-04 -1.4855102547E-04 1.0757287522E-04 - -3.0023992331E-04 6.2826824177E-05 1.2828261694E-04 - 2.5215986141E-04 2.1550978328E-04 -1.5558371625E-04 - -8.1369051134E-04 -2.7910643333E-06 1.7346862942E-04 - 2.0635069670E-04 -1.3893230694E-04 -4.7938274642E-04 - -1.2804682132E-04 -1.8705279778E-04 4.6935725481E-04 - 4.6074692214E-04 -7.8693508763E-05 -1.8028191091E-05 - -2.2723015053E-04 1.3311818368E-04 2.8963586298E-04 - 9.7364391612E-05 5.7623254353E-05 -1.4794910522E-04 - -4.4378699609E-04 -3.2068429350E-04 -4.7451860895E-04 - 4.0137606622E-04 3.0152545631E-04 1.4755249290E-04 - 1.0068818009E-04 1.0532426737E-05 3.1639364021E-04 + -8.8746124940E-05 5.0414516290E-04 3.0112914890E-04 + 1.3582220726E-04 -3.6204315410E-05 3.2160100035E-04 + 3.4546963096E-04 -2.3493535007E-04 -2.9927770304E-04 + -1.6125449362E-04 -4.1658950811E-05 -2.3906037763E-04 + 1.9640320132E-04 2.7826271306E-04 -3.3439522597E-05 + -1.5728475580E-04 3.1110350410E-04 -3.5580061254E-05 + -4.8231031773E-04 -3.3631527106E-04 2.1155786988E-04 + 1.3540318984E-05 1.3405722732E-04 2.4997008014E-04 + 8.6578013238E-05 -2.6885106804E-04 4.3623024705E-05 + -1.9736151462E-04 3.6397939209E-05 -3.2034550265E-04 + 2.9659264273E-05 6.3776295019E-05 -2.3766394998E-04 + 1.1815841584E-04 -2.5963023299E-04 3.1507548293E-04 + 3.8335780225E-04 3.9113291833E-05 2.7032102615E-04 + 4.8246423331E-04 2.4256383225E-04 -4.6042241842E-05 + -4.4298788410E-04 4.0578547062E-04 -1.9267522851E-04 + 3.8795881846E-06 -5.6520632461E-04 -2.7464212485E-05 + 1.6054458574E-04 1.0719735278E-04 1.2237079400E-04 + -1.8461454468E-04 4.0574978435E-05 8.0458092243E-05 + 2.3960205248E-04 -2.8882034869E-04 -6.4920058092E-04 + -2.8478362962E-04 1.2400838546E-05 -2.1250428535E-04 + 1.5389513453E-04 -1.3911716153E-04 9.8444931728E-05 + -3.1289664585E-04 5.6572387219E-05 6.4903201502E-05 + 2.5362189849E-04 2.3082688427E-04 -9.5151179618E-05 + -7.6373242145E-04 6.7049381319E-06 1.5180596099E-04 + 2.0820151074E-04 -1.6062330068E-04 -4.3613944764E-04 + -8.6332383570E-05 -1.9564773020E-04 4.5512291555E-04 + 4.0627931680E-04 -8.1813800405E-05 -3.0635681112E-07 + -2.1816086997E-04 1.5856828443E-04 2.4195939272E-04 + 5.6788284801E-05 2.8839587892E-05 -9.7648303464E-05 + -3.3734396902E-04 -3.6335231192E-04 -4.6928377158E-04 + 3.4301663623E-04 3.0711777023E-04 1.9310767211E-04 + 1.1095455523E-04 1.8870476233E-05 2.8140127591E-04 :F: - 5.6932913311E-05 -5.9706061516E-03 -1.6307558474E-03 - 1.0224506071E-02 -3.6559066606E-04 -7.3660427577E-03 - -2.5647419029E-02 1.0991015534E-02 -6.6402397437E-03 - 1.1626493363E-02 -1.0110079237E-03 1.1859303280E-02 - -2.0855991943E-03 -6.3475383176E-03 -7.9633704274E-04 - -2.7610198178E-03 -6.4948509952E-04 -1.4069670860E-03 - 1.1353672736E-02 5.2170920854E-03 -3.0391862570E-03 - 2.2618922120E-03 2.2131528522E-03 2.1538525530E-03 - -2.6309277310E-02 -1.7791391224E-03 -1.1105711805E-02 - 1.7260546770E-02 -7.5491710475E-03 2.3428107128E-02 - 2.2506178109E-03 2.3467946740E-03 5.0749600860E-03 - 1.1455992834E-02 1.3910876532E-05 -5.3297832744E-03 - -9.9385000471E-03 -3.1042124943E-04 1.3906304371E-04 - -4.4382425047E-03 -4.6126271579E-03 5.5392825716E-03 - 1.4626000538E-02 -8.2243085749E-03 -4.3576068837E-03 - 1.5437904156E-03 3.5788000818E-03 3.3220581552E-03 - 1.2767422811E-02 -4.1136868745E-04 -4.9954220526E-03 - -8.4816424026E-03 1.9597067444E-03 9.7176293029E-03 - 1.4038002077E-03 -5.5956597156E-03 -1.1307695672E-02 - -1.8978187573E-02 1.1366624041E-02 3.6710429931E-03 - 1.5622250858E-02 -2.5170217458E-03 2.2037971842E-03 - 2.1745735238E-03 1.9825292029E-03 1.4424067295E-02 - -1.2632016995E-03 -3.0937546500E-03 -1.1925145802E-02 - -8.8042013990E-03 -4.8300558498E-03 4.5875009667E-03 - -1.7652460654E-03 4.1142580533E-03 -9.8684405541E-03 - -8.7532949117E-03 2.1236123452E-03 1.0674814647E-03 - 1.2136731303E-02 -1.1911095545E-03 -3.3308449950E-03 - -3.0117188125E-03 -5.8562486784E-03 9.9529588847E-03 - 9.3165464226E-03 7.2289779737E-03 -1.0755856301E-02 - -2.4451593347E-02 1.0278836812E-02 -1.2574009593E-03 - 1.0877624393E-02 -3.1477380724E-04 -9.5991183154E-03 - -2.7025106980E-04 -2.7854232781E-03 7.5714504406E-03 -:LATVEC_SCALE: 1.5475641860E+01 1.5475641860E+01 1.5475641860E+01 + -1.3600278272E-03 -5.3793189578E-03 -1.3790431456E-03 + 1.0785731148E-02 1.1490864503E-04 -5.9448363884E-03 + -1.7213356127E-02 4.7993195746E-03 -6.5857802891E-03 + 9.3357048573E-03 -1.3100774451E-03 9.3103890679E-03 + -1.7880557633E-03 -6.2300738976E-03 -3.7802925450E-04 + -3.5280569930E-03 1.4363389563E-03 5.1909218415E-04 + 1.0403513410E-02 4.5239308207E-03 -3.7381295514E-04 + 6.6428528721E-04 1.3386067532E-03 -4.1409056454E-04 + -2.3053500215E-02 -4.2448936151E-04 -9.0960618010E-03 + 1.4266370959E-02 -3.8853699070E-03 1.7253196986E-02 + 1.4186972404E-03 7.3543158557E-04 2.8768451045E-03 + 7.4259135014E-03 1.2912608091E-04 -2.3117094348E-03 + -4.3845394614E-03 2.3116682941E-03 3.9184107419E-04 + -5.7545646803E-03 -5.2839771284E-03 2.5126780798E-03 + 1.0216026737E-02 -6.2937264366E-03 -1.7158667215E-03 + -9.9917346139E-04 -4.0992774828E-04 2.6076237722E-03 + 1.0274700568E-02 -1.7094785990E-03 -2.9044848933E-03 + -5.9143956050E-03 9.1083294011E-04 1.0846679159E-02 + 1.2595333269E-03 -4.2245196478E-03 -1.3534159036E-02 + -1.7740191097E-02 1.1172526488E-02 1.4888422977E-03 + 2.0419483485E-02 -3.2845977049E-03 2.0900199003E-03 + 3.6360647680E-04 3.9454565965E-04 1.5518191147E-02 + 2.3669121041E-03 -1.8402732123E-03 -1.5606829438E-02 + -1.8474486814E-02 1.7805515881E-03 5.2641389487E-03 + 1.7168112427E-03 3.8455502627E-03 -1.2002725620E-02 + -1.0572542086E-02 -6.3455472198E-04 7.2914689021E-03 + 1.4082975173E-02 1.4406472276E-03 -3.9096463869E-03 + -2.2205880363E-03 -3.3397447584E-03 1.1433519505E-02 + 9.6815037315E-03 5.4113034385E-03 -1.2885914216E-02 + -2.5620725301E-02 4.3268096902E-03 -2.4404490692E-03 + 1.6874306246E-02 9.3084980381E-04 -8.1159407313E-03 + -2.9318720252E-03 -1.3528182821E-03 1.0194853817E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6161554881E+03 +:LATVEC_SCALE: + 1.5349080555E+01 1.5349080555E+01 1.5349080555E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0829720440E+00 -3.8536759927E-02 5.6783969694E-02 - -3.8536759927E-02 -6.3258682418E-01 -1.5800314745E-01 - 5.6783969694E-02 -1.5800314745E-01 -8.9631032606E-01 + 1.0578483766E+00 1.5631328469E-02 -2.3528217708E-02 + 1.5631328469E-02 7.2973417022E-01 1.6729934233E-01 + -2.3528217708E-02 1.6729934233E-01 8.8622463336E-01 :STRESS: - -1.1639144219E+00 -4.9996545584E-01 1.6616707013E+00 - -4.9996545584E-01 1.5578040925E+00 5.4531831595E-02 - 1.6616707013E+00 5.4531831595E-02 2.1717868374E-01 -:PRESIO: 8.7062306475E-01 -:PRES: -2.0368945147E-01 -:PRESIG: 9.0180808469E-01 + -1.7853107348E+00 -3.6809953786E-01 1.3935380564E+00 + -3.6809953786E-01 1.7402992055E+00 3.6294457151E-02 + 1.3935380564E+00 3.6294457151E-02 -6.1686003907E-01 +:CONSTRESS: + 3.4753552394E+00 7.5247311657E-01 -2.7977641471E+00 + 7.5247311657E-01 -4.3387974906E+00 2.6285778005E-01 + -2.7977641471E+00 2.6285778005E-01 8.6344225122E-01 +:TOTSTRESS: + -6.3219612799E-01 -3.6874225025E-01 1.3806978730E+00 + -3.6874225025E-01 3.3282324553E+00 -1.3185289487E-01 + 1.3806978730E+00 -1.3185289487E-01 6.3964242122E-01 +:PRESIO: 8.9126906006E-01 +:PRES: 2.2062385611E-01 +:CONPRES: -1.3510271486E-13 +:TOTPRES: 1.1118929162E+00 +:PRESIG: 9.2001967490E-01 :MIND: -Al - Al: 4.8789778578E+00 -Si - Si: 4.7099243306E+00 -Al - Si: 4.6385892235E+00 -:MDSTEP: 39 -:MDTM: 1.30 +Al - Al: 4.6741010347E+00 +Si - Si: 4.7534231600E+00 +Al - Si: 4.8122374203E+00 + + +:MDSTEP: 29 +:MDTM: 5.60 :TWIST: 0 :TEL: 1120 -:TIO: 1121.5702040562 -:TEN: -3.2411652693E+00 -:KEN: 5.1612115422E-03 -:KENIG: 5.3277022371E-03 -:FEN: -3.2463264808E+00 -:UEN: -3.2456030287E+00 -:TSEN: -7.2345209960E-04 -:NPT_NP_HAMIL: -2.3401817065E-05 +:TIO: 1115.73681016924 +:TEN: -3.2409753223E+00 +:KEN: 5.1343675874E-03 +:KENIG: 5.2999923483E-03 +:FEN: -3.2461096899E+00 +:UEN: -3.2453192863E+00 +:TSEN: -7.9040351985E-04 +:NPT_NP_HAMIL: -8.1103184810E-04 +:SNOSE[0]: 1.0144420077E+00 +:SNOSE[1]: 4.2622022074E-05 :R: - 3.4447877290E-01 5.0514036259E-01 2.9764816024E-01 - 3.9694019100E+00 1.5454639430E+01 4.2015898655E+00 - 8.1193152978E+00 1.5257642728E+01 4.0179345850E-02 - 1.1439278257E+01 1.5456167843E+01 3.6147099522E+00 - 1.9365970606E-01 8.0394128052E+00 1.5463864415E+01 - 3.7296061327E+00 8.0480647125E+00 3.8332902638E+00 - 7.2462574488E+00 7.4080013026E+00 1.9947136408E-01 - 1.1636758962E+01 7.8797668422E+00 4.1249098109E+00 - 5.6651315906E-01 1.5228256737E+01 7.8099999244E+00 - 3.6417440963E+00 3.6630879001E-02 1.1269422899E+01 - 7.7709766605E+00 6.4453755949E-02 7.8262620086E+00 - 1.1720003792E+01 1.5236366046E+01 1.1925663442E+01 - 3.7426690117E-01 7.7766984776E+00 8.0091474098E+00 - 4.3670722924E+00 8.0021147363E+00 1.1577875147E+01 - 7.2961613024E+00 8.1593843715E+00 7.5546425577E+00 - 1.1634688313E+01 7.2042938163E+00 1.1586827651E+01 - 1.3697985411E-01 3.9887147108E+00 3.9956540672E+00 - 3.7055066157E+00 3.9122011235E+00 3.6315167333E-02 - 7.9668749169E+00 3.5968154595E+00 3.2913098091E+00 - 1.1394592305E+01 3.8555563845E+00 1.5287520159E+01 - 3.8534164693E-01 1.1493434092E+01 3.9759486788E+00 - 3.5784415271E+00 1.1680909198E+01 5.2357002168E-01 - 7.9680075835E+00 1.1850325444E+01 3.8494665112E+00 - 1.0960287931E+01 1.1608769694E+01 1.1440224850E-01 - 1.9090277879E-01 3.7061199491E+00 1.1233287309E+01 - 3.8251924390E+00 3.6860893506E+00 8.1460979561E+00 - 8.0968973997E+00 3.7842557881E+00 1.1637864938E+01 - 1.1414251810E+01 4.0329297429E+00 7.9584147902E+00 - 3.2432374237E-01 1.1639531602E+01 1.1581330121E+01 - 3.6266809075E+00 1.1268281583E+01 7.7999198775E+00 - 8.0119703075E+00 1.1920058509E+01 1.1850019648E+01 - 1.1755260786E+01 1.1639555279E+01 7.9708036507E+00 + 3.6508545680E-01 3.8146215682E-01 2.2112839430E-01 + 3.8954625692E+00 1.5339185344E+01 4.0945303830E+00 + 7.9854705409E+00 1.5187539544E+01 1.1952041015E-01 + 1.1378695473E+01 1.5343364304E+01 3.6366531892E+00 + 1.4526963579E-01 7.9117828873E+00 1.5348188017E+01 + 3.7414919890E+00 7.9074514377E+00 3.8112587714E+00 + 7.2975035228E+00 7.4273599819E+00 1.4623226418E-01 + 1.1539432508E+01 7.7822516881E+00 4.0309567161E+00 + 5.6191595810E-01 1.5173141975E+01 7.7447739035E+00 + 3.6485139137E+00 3.1300488321E-02 1.1241586875E+01 + 7.6988647343E+00 4.7898180132E-02 7.8198432693E+00 + 1.1589538651E+01 1.5177512371E+01 1.1755489141E+01 + 2.8164835495E-01 7.7041327077E+00 7.8777920849E+00 + 4.2179129865E+00 7.8827193188E+00 1.1493240829E+01 + 7.3362517071E+00 7.9997402858E+00 7.5430744364E+00 + 1.1541443353E+01 7.2845773904E+00 1.1498671453E+01 + 8.8295320362E-02 3.9311777912E+00 3.9368133142E+00 + 3.7269095519E+00 3.8697706526E+00 8.1996401602E-03 + 7.8428430578E+00 3.6424688840E+00 3.4338845464E+00 + 1.1386389356E+01 3.8135026297E+00 1.5215100258E+01 + 3.3244102005E-01 1.1436919134E+01 3.9181164256E+00 + 3.6256494447E+00 1.1571833759E+01 4.9415689816E-01 + 7.8407381631E+00 1.1700056234E+01 3.8516472142E+00 + 1.1070956454E+01 1.1515547699E+01 7.1714965838E-02 + 1.3716828632E-01 3.7129396589E+00 1.1258815589E+01 + 3.8225747559E+00 3.7035771935E+00 7.9641995891E+00 + 7.9219107644E+00 3.7735562675E+00 1.1547633178E+01 + 1.1378577600E+01 3.9653211106E+00 7.8264957223E+00 + 3.0143665394E-01 1.1534662162E+01 1.1520377994E+01 + 3.6974819572E+00 1.1261545037E+01 7.8557231042E+00 + 7.8529339724E+00 1.1749253800E+01 1.1714316794E+01 + 1.1635313129E+01 1.1542403157E+01 7.8313792328E+00 :V: - -9.2178218238E-05 4.6307704287E-04 2.9038747540E-04 - 1.9064707266E-04 -3.5012226600E-05 2.7747281562E-04 - 2.2113665108E-04 -1.8765212638E-04 -3.3197591392E-04 - -9.9190297376E-05 -4.7052507674E-05 -1.7706109267E-04 - 1.8142264727E-04 2.3762456943E-04 -3.5098470190E-05 - -1.7288160043E-04 3.0481431933E-04 -3.6694678141E-05 - -4.1149201032E-04 -3.0222184496E-04 1.9963581580E-04 - 2.0364877936E-05 1.4121420159E-04 2.4728568880E-04 - -5.5143092211E-05 -2.6994855721E-04 -1.4011966487E-05 - -1.0614028950E-04 4.5820974662E-06 -2.0074626458E-04 - 4.2002715414E-05 6.9062323323E-05 -2.1291681235E-04 - 1.6810892803E-04 -2.5296235206E-04 2.8696323821E-04 - 3.3741134260E-04 4.2674085469E-05 2.6723880031E-04 - 4.4509554428E-04 2.0945750789E-04 -2.2391631840E-05 - -3.6324590950E-04 3.5785350317E-04 -2.0393558064E-04 - 2.6748870881E-06 -5.4457645283E-04 -1.1622100382E-05 - 2.1638254756E-04 1.0020658883E-04 9.8079300228E-05 - -2.1975331997E-04 4.7469769827E-05 1.3210054746E-04 - 2.4114655716E-04 -3.0817369002E-04 -6.9848811803E-04 - -3.7217577518E-04 6.9957143997E-05 -1.9428168115E-04 - 2.3812630929E-04 -1.4946936666E-04 1.0842216568E-04 - -2.9858468110E-04 6.3659105056E-05 1.3499918296E-04 - 2.5104198443E-04 2.1358047161E-04 -1.6103706711E-04 - -8.1631137238E-04 -5.1209500165E-06 1.7533801108E-04 - 2.0508218294E-04 -1.3666353857E-04 -4.8319047277E-04 - -1.3202184780E-04 -1.8564980827E-04 4.6892957495E-04 - 4.6568892048E-04 -7.9111204222E-05 -1.9602515931E-05 - -2.2822947668E-04 1.3001879464E-04 2.9386602428E-04 - 1.0167346976E-04 6.1002837867E-05 -1.5285241701E-04 - -4.5471775946E-04 -3.1506924877E-04 -4.7417238259E-04 - 4.0582863356E-04 3.0076690619E-04 1.4261427115E-04 - 1.0035502766E-04 9.1643987153E-06 3.1941845220E-04 + -8.9155325807E-05 5.0019074228E-04 2.9969396878E-04 + 1.4092525530E-04 -3.6083225062E-05 3.1779668484E-04 + 3.3578024270E-04 -2.3184386491E-04 -3.0187337621E-04 + -1.5610236619E-04 -4.2218081794E-05 -2.3372791323E-04 + 1.9501870128E-04 2.7445238490E-04 -3.3550475729E-05 + -1.5868405944E-04 3.1107126680E-04 -3.5281516678E-05 + -4.7588862296E-04 -3.3320625394E-04 2.1079307959E-04 + 1.3881544172E-05 1.3443473035E-04 2.4922128383E-04 + 7.4678112050E-05 -2.6845584883E-04 3.8876173552E-05 + -1.8962140055E-04 3.4267131238E-05 -3.1073040072E-04 + 3.0299717964E-05 6.4044010782E-05 -2.3557174356E-04 + 1.2169260572E-04 -2.5895979248E-04 3.1307579327E-04 + 3.8010443512E-04 4.0161063295E-05 2.6985152160E-04 + 4.7843429667E-04 2.3932467750E-04 -4.4585484083E-05 + -4.3666679834E-04 4.0158474502E-04 -1.9314123516E-04 + 3.4265993386E-06 -5.6398589546E-04 -2.6074723416E-05 + 1.6520816964E-04 1.0614815347E-04 1.2061740419E-04 + -1.8708991061E-04 4.0942771813E-05 8.5486864628E-05 + 2.3961040706E-04 -2.9021881430E-04 -6.5413742558E-04 + -2.9273998359E-04 1.7807742057E-05 -2.1124219453E-04 + 1.6335911640E-04 -1.4038482131E-04 9.9241718459E-05 + -3.1192154800E-04 5.6653691311E-05 7.2262969906E-05 + 2.5405688619E-04 2.2935107087E-04 -1.0241052035E-04 + -7.7064008479E-04 7.4441673569E-06 1.5394480070E-04 + 2.0846029200E-04 -1.5836162193E-04 -4.4086961001E-04 + -9.1221682795E-05 -1.9545308359E-04 4.5740547826E-04 + 4.1210375071E-04 -8.0971004366E-05 -2.1776521396E-06 + -2.1872804717E-04 1.5652227673E-04 2.4692270201E-04 + 6.1318281603E-05 3.1450150066E-05 -1.0360566492E-04 + -3.4895683059E-04 -3.6026571564E-04 -4.6933672535E-04 + 3.5024832939E-04 3.0682824382E-04 1.8872754690E-04 + 1.0934448538E-04 1.8132140723E-05 2.8558736754E-04 :F: - 1.5899296975E-04 -5.8510303107E-03 -1.6664223142E-03 - 1.0050095602E-02 -4.2196550789E-04 -7.4215274060E-03 - -2.6327020912E-02 1.1680246416E-02 -6.5322911204E-03 - 1.1641609361E-02 -9.5992069513E-04 1.1983456531E-02 - -2.0117755175E-03 -6.2717763943E-03 -8.7703042904E-04 - -2.5654840932E-03 -9.4024136921E-04 -1.6264672359E-03 - 1.1292360303E-02 5.1423336973E-03 -3.2941479508E-03 - 2.4372938192E-03 2.3011500602E-03 2.4892370959E-03 - -2.6272547208E-02 -1.8923470486E-03 -1.1092486672E-02 - 1.7337539489E-02 -7.8323030718E-03 2.3781845034E-02 - 2.3506607792E-03 2.5189330434E-03 5.2357692671E-03 - 1.1833771265E-02 -8.8107370876E-06 -5.5465910535E-03 - -1.0471510905E-02 -7.0655196340E-04 1.5267049037E-04 - -4.2787805503E-03 -4.4192493307E-03 5.7376642758E-03 - 1.4807724811E-02 -8.2656974724E-03 -4.6632006671E-03 - 1.8885191979E-03 3.9801178978E-03 3.4210292930E-03 - 1.2978457273E-02 -3.1349970730E-04 -5.1489120547E-03 - -8.7257472596E-03 2.0532302816E-03 9.5913204399E-03 - 1.5991211046E-03 -5.6670728190E-03 -1.1219126936E-02 - -1.9034938348E-02 1.1237382639E-02 3.9575505737E-03 - 1.5011917916E-02 -2.3690783230E-03 2.1116319247E-03 - 2.2477532139E-03 2.1271338800E-03 1.4362804814E-02 - -1.5240736569E-03 -3.1868239502E-03 -1.1515060819E-02 - -7.8770314073E-03 -5.4758999486E-03 4.5882623934E-03 - -2.1156599564E-03 4.0715129490E-03 -9.6594469712E-03 - -8.5941573967E-03 2.4468165624E-03 4.7531250429E-04 - 1.1846169036E-02 -1.5246310070E-03 -3.2704677048E-03 - -3.0958672974E-03 -6.0911529635E-03 9.6011152513E-03 - 9.3926735005E-03 7.2961849395E-03 -1.0657134329E-02 - -2.4171100148E-02 1.0743014048E-02 -9.0031047439E-04 - 1.0199011683E-02 -4.5692015493E-04 -9.7991855869E-03 - -7.9766674983E-06 -2.9430836392E-03 7.4001398372E-03 -:LATVEC_SCALE: 1.5494622488E+01 1.5494622488E+01 1.5494622488E+01 + -1.1222338540E-03 -5.4520792225E-03 -1.4106590322E-03 + 1.0788053492E-02 1.6297021860E-05 -6.0537676049E-03 + -1.7920863592E-02 5.2057318815E-03 -6.6112162995E-03 + 9.5631259505E-03 -1.3123660525E-03 9.5529080135E-03 + -1.8120073145E-03 -6.2111764768E-03 -3.8550733146E-04 + -3.5471662630E-03 1.4406965766E-03 3.2285080434E-04 + 1.0435247103E-02 4.5719099967E-03 -6.1901685467E-04 + 8.2116079891E-04 1.4550393757E-03 -1.4482626096E-04 + -2.3358842800E-02 -6.0297233649E-04 -9.3298337716E-03 + 1.4559308306E-02 -4.2230921796E-03 1.7828907932E-02 + 1.4107450442E-03 9.4332455109E-04 3.1343581915E-03 + 7.7476530655E-03 2.5164581809E-05 -2.5843933907E-03 + -4.8295671949E-03 2.2264575773E-03 3.5512877666E-04 + -5.5863885743E-03 -5.2342716328E-03 2.8263149100E-03 + 1.0602656724E-02 -6.4655992616E-03 -1.9951964353E-03 + -7.6224994404E-04 -2.0405805873E-04 2.6440646346E-03 + 1.0613272703E-02 -1.5491755788E-03 -3.1115258732E-03 + -6.1719546272E-03 1.0170523708E-03 1.0745907857E-02 + 1.1841252677E-03 -4.4588358766E-03 -1.3396866881E-02 + -1.8005765418E-02 1.1298300139E-02 1.5905656713E-03 + 2.0241921625E-02 -3.3531845401E-03 2.1927083359E-03 + 5.2023786355E-04 5.1013426086E-04 1.5551657606E-02 + 1.9813247804E-03 -1.9382161656E-03 -1.5352433539E-02 + -1.7754025329E-02 1.3425704436E-03 5.1020182424E-03 + 1.4463668354E-03 3.8867764881E-03 -1.1931831305E-02 + -1.0502638030E-02 -5.2822269137E-04 6.7188324245E-03 + 1.4073819317E-02 1.2202465891E-03 -3.8274471377E-03 + -2.3168537585E-03 -3.5217212667E-03 1.1512082669E-02 + 9.6116621720E-03 5.6675908241E-03 -1.2717375371E-02 + -2.5765888883E-02 4.7760337869E-03 -2.4966697449E-03 + 1.6463003549E-02 9.6038803855E-04 -8.0452826272E-03 + -2.6072390149E-03 -1.5087431635E-03 9.9355433913E-03 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6312198807E+03 +:LATVEC_SCALE: + 1.5370365059E+01 1.5370365059E+01 1.5370365059E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0848596916E+00 -4.0337565014E-02 5.8580867947E-02 - -4.0337565014E-02 -6.2173676683E-01 -1.5601930221E-01 - 5.8580867947E-02 -1.5601930221E-01 -8.9534707885E-01 + 1.0582714528E+00 1.8139461531E-02 -2.7596891529E-02 + 1.8139461531E-02 7.1876397105E-01 1.6613921546E-01 + -2.7596891529E-02 1.6613921546E-01 8.8535686251E-01 :STRESS: - -1.0239243918E+00 -5.1574273494E-01 1.6665857892E+00 - -5.1574273494E-01 1.6015593807E+00 5.8222434077E-02 - 1.6665857892E+00 5.8222434077E-02 3.2654270264E-01 -:PRESIO: 8.6731451244E-01 -:PRES: -3.0139256385E-01 -:PRESIG: 8.9890402848E-01 + -1.5645216562E+00 -3.7841465214E-01 1.4123205685E+00 + -3.7841465214E-01 1.8235837979E+00 3.6489684069E-02 + 1.4123205685E+00 3.6489684069E-02 -3.4191697863E-01 +:CONSTRESS: + 3.4261265965E+00 7.7730747721E-01 -2.8459196657E+00 + 7.7730747721E-01 -4.1264244866E+00 2.6055851979E-01 + -2.8459196657E+00 2.6055851979E-01 7.0029789006E-01 +:TOTSTRESS: + -8.0333348752E-01 -3.8075336354E-01 1.4060022057E+00 + -3.8075336354E-01 3.0216046597E+00 -1.3090898840E-01 + 1.4060022057E+00 -1.3090898840E-01 5.2697595109E-01 +:PRESIO: 8.8746409546E-01 +:PRES: 2.7618278969E-02 +:CONPRES: 6.6454852364E-17 +:TOTPRES: 9.1508237443E-01 +:PRESIG: 9.1609196951E-01 :MIND: -Al - Al: 4.8825029777E+00 -Si - Si: 4.7063735669E+00 -Al - Si: 4.6250306979E+00 -:MDSTEP: 40 -:MDTM: 1.94 +Al - Al: 4.6697977389E+00 +Si - Si: 4.7525700973E+00 +Al - Si: 4.7964604436E+00 + + +:MDSTEP: 30 +:MDTM: 5.55 :TWIST: 0 :TEL: 1120 -:TIO: 1121.47410144788 -:TEN: -3.2411823939E+00 -:KEN: 5.1607692998E-03 -:KENIG: 5.3272457289E-03 -:FEN: -3.2463431632E+00 -:UEN: -3.2456176814E+00 -:TSEN: -7.2548184646E-04 -:NPT_NP_HAMIL: -2.4336249400E-05 +:TIO: 1116.13318044298 +:TEN: -3.2409982000E+00 +:KEN: 5.1361915935E-03 +:KENIG: 5.3018751933E-03 +:FEN: -3.2461343916E+00 +:UEN: -3.2453557335E+00 +:TSEN: -7.7865811058E-04 +:NPT_NP_HAMIL: -8.3677109715E-04 +:SNOSE[0]: 1.0153125199E+00 +:SNOSE[1]: 3.7174189491E-05 :R: - 3.4261716888E-01 5.1715672529E-01 3.0518511355E-01 - 3.9790932399E+00 1.5472619740E+01 4.2134973347E+00 - 8.1343699643E+00 1.5271752117E+01 3.1921662186E-02 - 1.1450920897E+01 1.5473844984E+01 3.6148823698E+00 - 1.9836576305E-01 8.0550290997E+00 1.5481848156E+01 - 3.7298404716E+00 8.0654228815E+00 3.8370370037E+00 - 7.2450430514E+00 7.4096146612E+00 2.0461973891E-01 - 1.1651489612E+01 7.8929068304E+00 4.1360996552E+00 - 5.6550973372E-01 1.5240121700E+01 7.8190415457E+00 - 3.6437735355E+00 3.6691225392E-02 1.1278493866E+01 - 7.7815264788E+00 6.6274953971E-02 7.8305994015E+00 - 1.1738613928E+01 1.5248685289E+01 1.1947252039E+01 - 3.8295236927E-01 7.7872337093E+00 8.0255407842E+00 - 4.3833739434E+00 8.0170108081E+00 1.1591515864E+01 - 7.2962470589E+00 8.1781009113E+00 7.5587474338E+00 - 1.1648971292E+01 7.1996395432E+00 1.1600717169E+01 - 1.4266387251E-01 3.9960594946E+00 4.0028965648E+00 - 3.7044775663E+00 3.9181743656E+00 3.9747544064E-02 - 7.9825875472E+00 3.5934998214E+00 3.2778843594E+00 - 1.1399042948E+01 3.8621279247E+00 1.5301403301E+01 - 3.9189177712E-01 1.1503723174E+01 3.9835105513E+00 - 3.5754360647E+00 1.1696761450E+01 5.2772589360E-01 - 7.9839292742E+00 1.1870035046E+01 3.8500343554E+00 - 1.0953338752E+01 1.1622738573E+01 1.1894108210E-01 - 1.9619140478E-01 3.7073039121E+00 1.1234903208E+01 - 3.8264846193E+00 3.6860156852E+00 8.1676593094E+00 - 8.1184549412E+00 3.7868938149E+00 1.1651536986E+01 - 1.1422484202E+01 4.0409977389E+00 7.9755193419E+00 - 3.2735120992E-01 1.1655329617E+01 1.1591543116E+01 - 3.6195487813E+00 1.1274350479E+01 7.7976760062E+00 - 8.0319213681E+00 1.1942046091E+01 1.1867891234E+01 - 1.1772087292E+01 1.1653946052E+01 7.9885299846E+00 + 3.6337440301E-01 3.9437960803E-01 2.2886925797E-01 + 3.9044664643E+00 1.5359700218E+01 4.1080982006E+00 + 8.0048416054E+00 1.5203014737E+01 1.1215069338E-01 + 1.1390762074E+01 1.5363724372E+01 3.6359859130E+00 + 1.5030314070E-01 7.9296017133E+00 1.5368775826E+01 + 3.7427522792E+00 7.9262213280E+00 3.8157046097E+00 + 7.2959390835E+00 7.4294827205E+00 1.5166624077E-01 + 1.1555889232E+01 7.7964612395E+00 4.0427701469E+00 + 5.6440821019E-01 1.5187651673E+01 7.7564910159E+00 + 3.6489896490E+00 3.2168549476E-02 1.1249674620E+01 + 7.7103720683E+00 4.9561079037E-02 7.8249289895E+00 + 1.1608785498E+01 1.5192267877E+01 1.1779654752E+01 + 2.9144878324E-01 7.7158973473E+00 7.8954903429E+00 + 4.2356443885E+00 7.8996315149E+00 1.1508193965E+01 + 7.3357162320E+00 8.0208368349E+00 7.5487952214E+00 + 1.1557633386E+01 7.2807409478E+00 1.1514090629E+01 + 9.2584322321E-02 3.9392912037E+00 3.9452844496E+00 + 3.7274292893E+00 3.8761948163E+00 1.0398256882E-02 + 7.8597465818E+00 3.6403204952E+00 3.4223555892E+00 + 1.1394905972E+01 3.8193356792E+00 1.5231102411E+01 + 3.3708280985E-01 1.1449377209E+01 3.9260626354E+00 + 3.6229686749E+00 1.1589395617E+01 4.9673439424E-01 + 7.8580022329E+00 1.1722070209E+01 3.8543883304E+00 + 1.1067168612E+01 1.1531814186E+01 7.5668019199E-02 + 1.4254426628E-01 3.7142136879E+00 1.1263512788E+01 + 3.8255822686E+00 3.7038906621E+00 7.9867133850E+00 + 7.9432849848E+00 3.7768203833E+00 1.1563674455E+01 + 1.1389015306E+01 3.9747210452E+00 7.8436201055E+00 + 3.0343767624E-01 1.1551577383E+01 1.1533809420E+01 + 3.6938238027E+00 1.1268347841E+01 7.8550201613E+00 + 7.8726904889E+00 1.1773277546E+01 1.1735305308E+01 + 1.1654253092E+01 1.1558955349E+01 7.8494609469E+00 :V: - -9.1884906335E-05 4.5906143216E-04 2.8887700602E-04 - 1.9526265985E-04 -3.5143518035E-05 2.7309651362E-04 - 2.0737829558E-04 -1.8134087978E-04 -3.3449443955E-04 - -9.3103204555E-05 -4.7426611872E-05 -1.7062179307E-04 - 1.7999057130E-04 2.3391898674E-04 -3.5458530953E-05 - -1.7377236795E-04 3.0363584689E-04 -3.7428129110E-05 - -4.0485793376E-04 -2.9893506148E-04 1.9751635784E-04 - 2.1544091120E-05 1.4204525058E-04 2.4796591046E-04 - -6.8234688171E-05 -2.7027600461E-04 -1.9560798429E-05 - -9.7171168693E-05 6.3061903013E-07 -1.8831571734E-04 - 4.3088265573E-05 7.0169920986E-05 -2.0978968073E-04 - 1.7367413985E-04 -2.5238139428E-04 2.8350836058E-04 - 3.3136171503E-04 4.2219825281E-05 2.6669718877E-04 - 4.4191263313E-04 2.0674921898E-04 -1.9452870890E-05 - -3.5495470251E-04 3.5286643907E-04 -2.0580996471E-04 - 3.6189178744E-06 -5.4131360275E-04 -9.8738917924E-06 - 2.2215543179E-04 9.9823154645E-05 9.5363410896E-05 - -2.2346269680E-04 4.8352423908E-05 1.3643117257E-04 - 2.4136150482E-04 -3.1019992444E-04 -7.0229490287E-04 - -3.8051575904E-04 7.5227263742E-05 -1.9191905506E-04 - 2.4483182486E-04 -1.5026865612E-04 1.0919199785E-04 - -2.9680717770E-04 6.4540018783E-05 1.4162957623E-04 - 2.4972431928E-04 2.1154574500E-04 -1.6623064110E-04 - -8.1822997013E-04 -7.7560811179E-06 1.7715016270E-04 - 2.0358490989E-04 -1.3437916109E-04 -4.8674155724E-04 - -1.3587063887E-04 -1.8403742754E-04 4.6807416516E-04 - 4.7033754020E-04 -7.9665117217E-05 -2.1138056195E-05 - -2.2919782474E-04 1.2677352526E-04 2.9782703570E-04 - 1.0597848403E-04 6.4388553362E-05 -1.5765022048E-04 - -4.6534948593E-04 -3.0914709465E-04 -4.7351027891E-04 - 4.0981956321E-04 2.9985001917E-04 1.3754743734E-04 - 1.0011893599E-04 7.7205410804E-06 3.2225640760E-04 + -8.9462960284E-05 4.9630670389E-04 2.9830216498E-04 + 1.4603873937E-04 -3.6017841222E-05 3.1400702344E-04 + 3.2581964076E-04 -2.2859033420E-04 -3.0452791035E-04 + -1.5088079526E-04 -4.2782804834E-05 -2.2833078998E-04 + 1.9366466906E-04 2.7071325029E-04 -3.3672753327E-05 + -1.6011434963E-04 3.1109310298E-04 -3.5090879592E-05 + -4.6955776594E-04 -3.3014508818E-04 2.0994378494E-04 + 1.4304157328E-05 1.3489296397E-04 2.4865901057E-04 + 6.2674198901E-05 -2.6820128522E-04 3.4035621930E-05 + -1.8179159335E-04 3.1978120022E-05 -3.0090953563E-04 + 3.0941632637E-05 6.4427179426E-05 -2.3340069449E-04 + 1.2540355869E-04 -2.5839007706E-04 3.1100144937E-04 + 3.7670255314E-04 4.1164750570E-05 2.6941426382E-04 + 4.7458900791E-04 2.3616720602E-04 -4.2982953788E-05 + -4.3025089676E-04 3.9738325711E-04 -1.9378266121E-04 + 3.0965877845E-06 -5.6276433269E-04 -2.4674955284E-05 + 1.7004954488E-04 1.0519775032E-04 1.1878972182E-04 + -1.8971964862E-04 4.1368342011E-05 9.0468170690E-05 + 2.3963613546E-04 -2.9177752104E-04 -6.5911678138E-04 + -3.0085616557E-04 2.3259434411E-05 -2.0996787403E-04 + 1.7273477533E-04 -1.4170457862E-04 1.0009973588E-04 + -3.1093320516E-04 5.6801119656E-05 7.9631413340E-05 + 2.5435515597E-04 2.2787300535E-04 -1.0954587594E-04 + -7.7731714007E-04 7.9662923787E-06 1.5603367241E-04 + 2.0862602566E-04 -1.5611583127E-04 -4.4563000019E-04 + -9.6080134794E-05 -1.9523848530E-04 4.5948871327E-04 + 4.1797879580E-04 -8.0255164936E-05 -4.0042854053E-06 + -2.1938132133E-04 1.5442303861E-04 2.5194391832E-04 + 6.5819166397E-05 3.4181337453E-05 -1.0948694742E-04 + -3.6066791585E-04 -3.5703542763E-04 -4.6949175091E-04 + 3.5731950514E-04 3.0660576677E-04 1.8442143433E-04 + 1.0791458043E-04 1.7322922034E-05 2.8969170319E-04 :F: - 2.5083765855E-04 -5.7076170877E-03 -1.6996610827E-03 - 9.8576694383E-03 -4.7903270210E-04 -7.4743238045E-03 - -2.6986777957E-02 1.2379701373E-02 -6.4099736869E-03 - 1.1623115962E-02 -9.0705471386E-04 1.2086578711E-02 - -1.9205957786E-03 -6.1926776956E-03 -9.6140048136E-04 - -2.3525522603E-03 -1.2595118347E-03 -1.8449131103E-03 - 1.1225783000E-02 5.0477516126E-03 -3.5405907034E-03 - 2.6116007674E-03 2.3940988198E-03 2.8250464731E-03 - -2.6193992415E-02 -1.9922407920E-03 -1.1048468453E-02 - 1.7384784532E-02 -8.0965308423E-03 2.4100332494E-02 - 2.4697852834E-03 2.6879664994E-03 5.3909281150E-03 - 1.2211038585E-02 -2.2386765276E-05 -5.7535921690E-03 - -1.1004937820E-02 -1.1335485153E-03 1.7620562927E-04 - -4.1313579764E-03 -4.2159576656E-03 5.9099273812E-03 - 1.4959122035E-02 -8.2838614574E-03 -4.9690436073E-03 - 2.2434671949E-03 4.3882013339E-03 3.5284651820E-03 - 1.3194063811E-02 -2.2472133192E-04 -5.2928984980E-03 - -8.9729132168E-03 2.1455874328E-03 9.4731334868E-03 - 1.8113917951E-03 -5.7165856753E-03 -1.1150457041E-02 - -1.9073668459E-02 1.1083529347E-02 4.2534051902E-03 - 1.4369887603E-02 -2.1978483021E-03 1.9984176878E-03 - 2.3070671282E-03 2.2743801248E-03 1.4310148642E-02 - -1.7714888750E-03 -3.2750864870E-03 -1.1093465524E-02 - -6.9607574700E-03 -6.1233991031E-03 4.6029419274E-03 - -2.4704052168E-03 4.0168152687E-03 -9.4534951974E-03 - -8.4389774531E-03 2.7872822213E-03 -1.0825213549E-04 - 1.1543355493E-02 -1.8653731685E-03 -3.2187916912E-03 - -3.1826411812E-03 -6.3420929125E-03 9.2309454103E-03 - 9.4834692713E-03 7.3388241209E-03 -1.0584404646E-02 - -2.3845075783E-02 1.1198079915E-02 -5.0840513940E-04 - 9.5149677889E-03 -6.0904139527E-04 -1.0022749302E-02 - 2.4473451539E-04 -3.0976496215E-03 7.2484099432E-03 -:LATVEC_SCALE: 1.5513524313E+01 1.5513524313E+01 1.5513524313E+01 + -8.9581904088E-04 -5.4999089931E-03 -1.4378102619E-03 + 1.0772287780E-02 -7.8940445929E-05 -6.1528184823E-03 + -1.8624099491E-02 5.6397719829E-03 -6.6244030443E-03 + 9.7727007472E-03 -1.3068281737E-03 9.7864263742E-03 + -1.8215991341E-03 -6.1821537306E-03 -3.9965060175E-04 + -3.5488768154E-03 1.4248527143E-03 1.1906695272E-04 + 1.0448169629E-02 4.6048406270E-03 -8.6950785229E-04 + 9.8051297935E-04 1.5650259100E-03 1.3850905250E-04 + -2.3631363732E-02 -7.8431082818E-04 -9.5404748716E-03 + 1.4832168897E-02 -4.5581903925E-03 1.8385214395E-02 + 1.4084415269E-03 1.1498020775E-03 3.3804154918E-03 + 8.0722049460E-03 -7.6500611241E-05 -2.8540641557E-03 + -5.2804680977E-03 2.1172421507E-03 3.1953883697E-04 + -5.4063665000E-03 -5.1636018360E-03 3.1373710152E-03 + 1.0968377759E-02 -6.6274498392E-03 -2.2764142510E-03 + -5.1761859615E-04 1.5471777933E-05 2.6802886982E-03 + 1.0929737563E-02 -1.3915681837E-03 -3.3196571484E-03 + -6.4348993603E-03 1.1222205163E-03 1.0634568798E-02 + 1.1502444813E-03 -4.6809227823E-03 -1.3263150226E-02 + -1.8256443911E-02 1.1396519813E-02 1.7112538137E-03 + 2.0022615146E-02 -3.4060707090E-03 2.2757860792E-03 + 6.6357850445E-04 6.2578138091E-04 1.5570655127E-02 + 1.6140391063E-03 -2.0372278403E-03 -1.5087279772E-02 + -1.7005793187E-02 8.8486778671E-04 4.9619386310E-03 + 1.1771974070E-03 3.9214886729E-03 -1.1840191478E-02 + -1.0423427886E-02 -4.0249530334E-04 6.1440373021E-03 + 1.4037021370E-02 9.8534858940E-04 -3.7415365774E-03 + -2.4165507760E-03 -3.6978532128E-03 1.1534279110E-02 + 9.5586572467E-03 5.9113184109E-03 -1.2550830589E-02 + -2.5875297385E-02 5.2228463532E-03 -2.5080760114E-03 + 1.6016198585E-02 9.7323213879E-04 -7.9950880515E-03 + -2.2855297613E-03 -1.6666080208E-03 9.6816036965E-03 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 3.6464466553E+03 +:LATVEC_SCALE: + 1.5391819256E+01 1.5391819256E+01 1.5391819256E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 1.0000000000E+00 0.0000000000E+00 + 6.1232339957E-17 6.1232339957E-17 1.0000000000E+00 :STRIO: - -1.0862350719E+00 -4.1952791388E-02 6.0157677842E-02 - -4.1952791388E-02 -6.1060582512E-01 -1.5380555866E-01 - 6.0157677842E-02 -1.5380555866E-01 -8.9380646519E-01 + 1.0592928079E+00 2.0611891556E-02 -3.1411814385E-02 + 2.0611891556E-02 7.0812395663E-01 1.6499691238E-01 + -3.1411814385E-02 1.6499691238E-01 8.8479982260E-01 :STRESS: - -8.8871620171E-01 -5.3169020725E-01 1.6694460835E+00 - -5.3169020725E-01 1.6429326163E+00 6.1947274411E-02 - 1.6694460835E+00 6.1947274411E-02 4.1875776723E-01 -:PRESIO: 8.6354912072E-01 -:PRES: -3.9099139394E-01 -:PRESIG: 8.9554558854E-01 + -1.3506232947E+00 -3.8953977294E-01 1.4286931819E+00 + -3.8953977294E-01 1.9103141013E+00 3.7114364351E-02 + 1.4286931819E+00 3.7114364351E-02 -7.8878284387E-02 +:CONSTRESS: + 3.3814375453E+00 8.0370271378E-01 -2.8890085969E+00 + 8.0370271378E-01 -3.9311116931E+00 2.5747147262E-01 + -2.8890085969E+00 2.5747147262E-01 5.4967414772E-01 +:TOTSTRESS: + -9.7152144274E-01 -3.9355104928E-01 1.4289036006E+00 + -3.9355104928E-01 2.7289215484E+00 -1.2958892459E-01 + 1.4289036006E+00 -1.2958892459E-01 4.1400395927E-01 +:PRESIO: 8.8407219572E-01 +:PRES: -1.6027084073E-01 +:CONPRES: 1.6829691361E-13 +:TOTPRES: 7.2380135499E-01 +:PRESIG: 9.1259065365E-01 :MIND: -Al - Al: 4.8865078585E+00 -Si - Si: 4.7026232687E+00 -Al - Si: 4.6118821807E+00 +Al - Al: 4.6661364226E+00 +Si - Si: 4.7515200997E+00 +Al - Si: 4.7808881152E+00 diff --git a/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.refout b/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.refout index 5987768b..0ae7aa5b 100644 --- a/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.refout +++ b/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.refout @@ -1,8 +1,8 @@ *************************************************************************** -* SPARC (version June 24, 2024) * +* SPARC (version December 03, 2025) * * Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * * Distributed under GNU General Public License 3 (GPL) * -* Start time: Sun Aug 11 19:39:10 2024 * +* Start time: Mon Apr 6 12:08:21 2026 * *************************************************************************** Input parameters *************************************************************************** @@ -11,7 +11,7 @@ LATVEC: 1.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 -FD_GRID: 43 43 43 +FD_GRID: 60 60 60 FD_ORDER: 12 BC: P P P KPOINT_GRID: 1 1 1 @@ -20,8 +20,9 @@ SPIN_TYP: 0 ELEC_TEMP_TYPE: Fermi-Dirac ELEC_TEMP: 1120 EXCHANGE_CORRELATION: GGA_PBE +HUBBARD_FLAG: 0 NSTATES: 76 -CHEB_DEGREE: 22 +CHEB_DEGREE: 30 CHEFSI_BOUND_FLAG: 0 CALC_STRESS: 1 TWTIME: 1E+09 @@ -34,9 +35,10 @@ ION_VEL_DSTR_RAND: 0 ION_TEMP: 1120 NPT_SCALE_VECS: 1 2 3 NPT_SCALE_CONSTRAINTS: 123 +NPT_NP_ANGLES: 0 NPT_NP_QMASS: 500 NPT_NP_BMASS: 0.1 -TARGET_PRESSURE: 0 GPa +TARGET_STRESS: 0 0 0 0 0 0 GPa RESTART_FLAG: 1 MAXIT_SCF: 100 MINIT_SCF: 2 @@ -48,7 +50,7 @@ TOL_LANCZOS: 1.00E-02 TOL_PSEUDOCHARGE: 5.00E-10 MIXING_VARIABLE: density MIXING_PRECOND: kerker -TOL_PRECOND: 1.22E-04 +TOL_PRECOND: 6.25E-05 PRECOND_KERKER_KTF: 1 PRECOND_KERKER_THRESH: 0 MIXING_PARAMETER: 1 @@ -69,7 +71,7 @@ PRINT_VELS: 1 PRINT_RESTART: 1 PRINT_RESTART_FQ: 1 PRINT_ENERGY_DENSITY: 0 -OUTPUT_FILE: Al16Si16_NPTNP_restart/temp_run/Al16Si16_NPTNP_restart +OUTPUT_FILE: Al16Si16_NPTNP_restart *************************************************************************** Cell *************************************************************************** @@ -84,490 +86,495 @@ Density: 2.6105618252E-01 (amu/Bohr^3), 2.9253624436E+00 (g/cc) *************************************************************************** NP_SPIN_PARAL: 1 NP_KPOINT_PARAL: 1 -NP_BAND_PARAL: 6 -NP_DOMAIN_PARAL: 2 2 2 -NP_DOMAIN_PHI_PARAL: 3 4 4 +NP_BAND_PARAL: 7 +NP_DOMAIN_PARAL: 5 1 1 +NP_DOMAIN_PHI_PARAL: 3 3 4 EIG_SERIAL_MAXNS: 1500 *************************************************************************** Initialization *************************************************************************** -Number of processors : 48 -Mesh spacing : 0.348837 (Bohr) +Number of processors : 36 +Mesh spacing : 0.25 (Bohr) Number of symmetry adapted k-points: 1 -Output printed to : Al16Si16_NPTNP_restart/temp_run/Al16Si16_NPTNP_restart.out -MD output printed to : Al16Si16_NPTNP_restart/temp_run/Al16Si16_NPTNP_restart.aimd +Output printed to : Al16Si16_NPTNP_restart.out_01 +MD output printed to : Al16Si16_NPTNP_restart.aimd_01 Total number of atom types : 2 Total number of atoms : 32 Total number of electrons : 112 Atom type 1 (valence electrons) : Al 3 -Pseudopotential : ../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +Pseudopotential : ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 Atomic mass : 26.9815385 -Pseudocharge radii of atom type 1 : 8.02 8.02 8.02 (x, y, z dir) +Pseudocharge radii of atom type 1 : 7.50 7.50 7.50 (x, y, z dir) Number of atoms of type 1 : 16 Atom type 2 (valence electrons) : Si 4 -Pseudopotential : ../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 +Pseudopotential : ../../../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 Atomic mass : 28.085 -Pseudocharge radii of atom type 2 : 8.02 8.02 8.02 (x, y, z dir) +Pseudocharge radii of atom type 2 : 7.50 7.50 7.50 (x, y, z dir) Number of atoms of type 2 : 16 -Estimated total memory usage : 349.47 MB -Estimated memory per processor : 7.28 MB +Estimated total memory usage : 946.98 MB +Estimated memory per processor : 26.30 MB *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.3240291435853 15.3240291435853 15.3240291435853 -CHEB_DEGREE: 22 +LATVEC_SCALE: 15.208810074 15.208810074 15.208810074 +CHEB_DEGREE: 30 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.356373 (Bohr) +Mesh spacing : 0.25348 (Bohr) =================================================================== - Self Consistent Field (SCF#30) + Self Consistent Field (SCF#20) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2361523069E+00 1.290E-01 0.509 -2 -3.2426116274E+00 4.311E-02 0.139 -3 -3.2445871023E+00 1.977E-02 0.127 -4 -3.2454754190E+00 1.440E-02 0.126 -5 -3.2458656422E+00 9.557E-03 0.127 -6 -3.2460190138E+00 4.649E-03 0.125 -7 -3.2460737092E+00 1.740E-03 0.125 -8 -3.2460922332E+00 1.183E-03 0.123 -9 -3.2460980671E+00 5.558E-04 0.142 -10 -3.2460999404E+00 4.472E-04 0.122 -11 -3.2461005508E+00 2.870E-04 0.121 -12 -3.2461007422E+00 1.699E-04 0.121 -13 -3.2461008024E+00 2.975E-05 0.119 -14 -3.2461008247E+00 2.039E-05 0.118 -15 -3.2461008320E+00 9.520E-06 0.118 -16 -3.2461008347E+00 1.977E-06 0.118 -17 -3.2461008356E+00 3.114E-06 0.117 -18 -3.2461008358E+00 1.413E-06 0.144 -19 -3.2461008361E+00 1.611E-06 0.118 -20 -3.2461008362E+00 2.554E-07 0.117 -Total number of SCF: 20 +1 -3.2327945271E+00 1.230E-01 2.191 +2 -3.2423753620E+00 4.627E-02 0.591 +3 -3.2447000872E+00 2.234E-02 0.600 +4 -3.2454694285E+00 1.312E-02 0.611 +5 -3.2457086369E+00 7.041E-03 0.600 +6 -3.2457902594E+00 3.384E-03 0.599 +7 -3.2458188847E+00 1.615E-03 0.598 +8 -3.2458290995E+00 8.074E-04 0.602 +9 -3.2458327611E+00 3.134E-04 0.589 +10 -3.2458340860E+00 1.253E-04 0.560 +11 -3.2458345651E+00 5.932E-05 0.574 +12 -3.2458347392E+00 4.752E-05 0.565 +13 -3.2458348013E+00 1.517E-05 0.566 +14 -3.2458348240E+00 2.793E-05 0.562 +15 -3.2458348325E+00 5.614E-06 0.562 +16 -3.2458348356E+00 5.084E-06 0.564 +17 -3.2458348363E+00 8.752E-07 0.566 +18 -3.2458348369E+00 2.666E-06 0.570 +19 -3.2458348370E+00 1.265E-06 0.547 +20 -3.2458348371E+00 9.493E-07 0.556 +21 -3.2458348371E+00 1.989E-07 0.553 +Total number of SCF: 21 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2461008362E+00 (Ha/atom) -Total free energy : -1.0387522676E+02 (Ha) -Band structure energy : 4.4435756180E+00 (Ha) -Exchange correlation energy : -4.1745544350E+01 (Ha) -Self and correction energy : -1.6501144711E+02 (Ha) --Entropy*kb*T : -2.4745989064E-02 (Ha) -Fermi level : 1.9816710044E-01 (Ha) -RMS force : 1.3281979967E-02 (Ha/Bohr) -Maximum force : 2.7073178911E-02 (Ha/Bohr) -Time for force calculation : 0.066 (sec) -Pressure : 8.3686531467E-01 (GPa) -Maximum stress : 2.4727570483E+00 (GPa) -Time for stress calculation : 0.124 (sec) -MD step time : 3.169 (sec) +Free energy per atom : -3.2458348371E+00 (Ha/atom) +Total free energy : -1.0386671479E+02 (Ha) +Band structure energy : 5.1405932368E+00 (Ha) +Exchange correlation energy : -4.1880877463E+01 (Ha) +Self and correction energy : -1.6501196095E+02 (Ha) +-Entropy*kb*T : -2.9763329322E-02 (Ha) +Fermi level : 2.0509018080E-01 (Ha) +RMS force : 1.2169314847E-02 (Ha/Bohr) +Maximum force : 2.3706220373E-02 (Ha/Bohr) +Time for force calculation : 0.093 (sec) +Pressure : 1.6188720968E+00 (GPa) +Maximum stress : 3.4690459776E+00 (GPa) +Time for stress calculation : 0.183 (sec) +MD step time : 14.362 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.3426631556158 15.3426631556158 15.3426631556158 -CHEB_DEGREE: 22 +LATVEC_SCALE: 15.2275885821129 15.2275885821129 15.2275885821129 +CHEB_DEGREE: 30 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.356806 (Bohr) +Mesh spacing : 0.253793 (Bohr) =================================================================== - Self Consistent Field (SCF#31) + Self Consistent Field (SCF#21) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462041586E+00 1.454E-02 0.131 -2 -3.2461373000E+00 5.052E-03 0.124 -3 -3.2461341093E+00 1.791E-03 0.134 -4 -3.2461336062E+00 8.299E-04 0.123 -5 -3.2461334624E+00 1.042E-04 0.120 -6 -3.2461334608E+00 2.661E-05 0.119 -7 -3.2461334590E+00 9.165E-06 0.117 -8 -3.2461334609E+00 3.433E-06 0.117 -9 -3.2461334600E+00 9.727E-07 0.114 -10 -3.2461334603E+00 3.340E-07 0.113 +1 -3.2459440756E+00 1.438E-02 0.625 +2 -3.2458825156E+00 5.941E-03 0.606 +3 -3.2458774710E+00 2.441E-03 0.597 +4 -3.2458763081E+00 8.410E-04 0.589 +5 -3.2458761631E+00 1.169E-04 0.589 +6 -3.2458761608E+00 2.278E-05 0.560 +7 -3.2458761595E+00 1.027E-05 0.579 +8 -3.2458761608E+00 3.438E-06 0.576 +9 -3.2458761598E+00 1.028E-06 0.562 +10 -3.2458761603E+00 3.034E-07 0.568 Total number of SCF: 10 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2461334603E+00 (Ha/atom) -Total free energy : -1.0387627073E+02 (Ha) -Band structure energy : 4.3358913714E+00 (Ha) -Exchange correlation energy : -4.1721854108E+01 (Ha) -Self and correction energy : -1.6501143885E+02 (Ha) --Entropy*kb*T : -2.4364523326E-02 (Ha) -Fermi level : 1.9705991656E-01 (Ha) -RMS force : 1.3338510628E-02 (Ha/Bohr) -Maximum force : 2.7433784700E-02 (Ha/Bohr) -Time for force calculation : 0.065 (sec) -Pressure : 6.8725688823E-01 (GPa) -Maximum stress : 2.2913279622E+00 (GPa) -Time for stress calculation : 0.121 (sec) -MD step time : 1.456 (sec) +Free energy per atom : -3.2458761603E+00 (Ha/atom) +Total free energy : -1.0386803713E+02 (Ha) +Band structure energy : 5.0355500885E+00 (Ha) +Exchange correlation energy : -4.1853881446E+01 (Ha) +Self and correction energy : -1.6501195581E+02 (Ha) +-Entropy*kb*T : -2.9090239833E-02 (Ha) +Fermi level : 2.0400211019E-01 (Ha) +RMS force : 1.2318473843E-02 (Ha/Bohr) +Maximum force : 2.4045755006E-02 (Ha/Bohr) +Time for force calculation : 0.092 (sec) +Pressure : 1.4225658815E+00 (GPa) +Maximum stress : 3.2197883779E+00 (GPa) +Time for stress calculation : 0.183 (sec) +MD step time : 6.355 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.3614506854982 15.3614506854982 15.3614506854982 -CHEB_DEGREE: 22 +LATVEC_SCALE: 15.2468696184267 15.2468696184267 15.2468696184267 +CHEB_DEGREE: 30 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.357243 (Bohr) +Mesh spacing : 0.254114 (Bohr) =================================================================== - Self Consistent Field (SCF#32) + Self Consistent Field (SCF#22) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462356341E+00 1.459E-02 0.130 -2 -3.2461681541E+00 4.982E-03 0.125 -3 -3.2461651117E+00 1.718E-03 0.123 -4 -3.2461646706E+00 8.241E-04 0.122 -5 -3.2461645289E+00 1.051E-04 0.120 -6 -3.2461645274E+00 2.718E-05 0.120 -7 -3.2461645256E+00 8.945E-06 0.118 -8 -3.2461645275E+00 3.365E-06 0.116 -9 -3.2461645265E+00 9.723E-07 0.114 -10 -3.2461645268E+00 3.395E-07 0.114 +1 -3.2459839834E+00 1.439E-02 0.610 +2 -3.2459218495E+00 5.817E-03 0.607 +3 -3.2459171077E+00 2.371E-03 0.600 +4 -3.2459160279E+00 8.410E-04 0.596 +5 -3.2459158828E+00 1.156E-04 0.591 +6 -3.2459158805E+00 2.224E-05 0.587 +7 -3.2459158792E+00 9.315E-06 0.579 +8 -3.2459158805E+00 3.351E-06 0.577 +9 -3.2459158796E+00 1.060E-06 0.561 +10 -3.2459158801E+00 3.084E-07 0.570 Total number of SCF: 10 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2461645268E+00 (Ha/atom) -Total free energy : -1.0387726486E+02 (Ha) -Band structure energy : 4.2273228762E+00 (Ha) -Exchange correlation energy : -4.1698256089E+01 (Ha) -Self and correction energy : -1.6501143069E+02 (Ha) --Entropy*kb*T : -2.4031918542E-02 (Ha) -Fermi level : 1.9594044907E-01 (Ha) -RMS force : 1.3386946780E-02 (Ha/Bohr) -Maximum force : 2.7748357464E-02 (Ha/Bohr) -Time for force calculation : 0.064 (sec) -Pressure : 5.4177307036E-01 (GPa) -Maximum stress : 2.1146822360E+00 (GPa) -Time for stress calculation : 0.122 (sec) -MD step time : 1.443 (sec) +Free energy per atom : -3.2459158801E+00 (Ha/atom) +Total free energy : -1.0386930816E+02 (Ha) +Band structure energy : 4.9277557375E+00 (Ha) +Exchange correlation energy : -4.1826370938E+01 (Ha) +Self and correction energy : -1.6501195074E+02 (Ha) +-Entropy*kb*T : -2.8444366235E-02 (Ha) +Fermi level : 2.0288708354E-01 (Ha) +RMS force : 1.2456302649E-02 (Ha/Bohr) +Maximum force : 2.4469087497E-02 (Ha/Bohr) +Time for force calculation : 0.093 (sec) +Pressure : 1.2229008251E+00 (GPa) +Maximum stress : 2.9715680298E+00 (GPa) +Time for stress calculation : 0.181 (sec) +MD step time : 6.259 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.3803615464208 15.3803615464208 15.3803615464208 -CHEB_DEGREE: 22 +LATVEC_SCALE: 15.2666004314681 15.2666004314681 15.2666004314681 +CHEB_DEGREE: 30 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.357683 (Bohr) +Mesh spacing : 0.254443 (Bohr) =================================================================== - Self Consistent Field (SCF#33) + Self Consistent Field (SCF#23) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2461923464E+00 1.089E-03 0.125 -2 -3.2461936230E+00 2.044E-04 0.119 -3 -3.2461936596E+00 8.710E-05 0.119 -4 -3.2461936621E+00 3.536E-05 0.118 -5 -3.2461936626E+00 1.959E-05 0.118 -6 -3.2461936626E+00 5.723E-06 0.136 -7 -3.2461936627E+00 2.452E-06 0.124 -8 -3.2461936628E+00 8.478E-07 0.113 -9 -3.2461936629E+00 2.533E-07 0.111 +1 -3.2459508909E+00 1.817E-03 0.604 +2 -3.2459536710E+00 2.267E-04 0.587 +3 -3.2459537168E+00 1.031E-04 0.588 +4 -3.2459537213E+00 4.512E-05 0.566 +5 -3.2459537212E+00 2.347E-05 0.583 +6 -3.2459537213E+00 7.388E-06 0.581 +7 -3.2459537218E+00 3.942E-06 0.578 +8 -3.2459537217E+00 1.490E-06 0.571 +9 -3.2459537212E+00 4.326E-07 0.569 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2461936629E+00 (Ha/atom) -Total free energy : -1.0387819721E+02 (Ha) -Band structure energy : 4.1180731508E+00 (Ha) -Exchange correlation energy : -4.1674805532E+01 (Ha) -Self and correction energy : -1.6501142298E+02 (Ha) --Entropy*kb*T : -2.3750377522E-02 (Ha) -Fermi level : 1.9481027679E-01 (Ha) -RMS force : 1.3428333842E-02 (Ha/Bohr) -Maximum force : 2.8015672481E-02 (Ha/Bohr) -Time for force calculation : 0.065 (sec) -Pressure : 4.0120858928E-01 (GPa) -Maximum stress : 1.9430353677E+00 (GPa) -Time for stress calculation : 0.121 (sec) -MD step time : 1.323 (sec) +Free energy per atom : -3.2459537212E+00 (Ha/atom) +Total free energy : -1.0387051908E+02 (Ha) +Band structure energy : 4.8175044306E+00 (Ha) +Exchange correlation energy : -4.1798448296E+01 (Ha) +Self and correction energy : -1.6501194564E+02 (Ha) +-Entropy*kb*T : -2.7828027839E-02 (Ha) +Fermi level : 2.0174739528E-01 (Ha) +RMS force : 1.2582589213E-02 (Ha/Bohr) +Maximum force : 2.4860958123E-02 (Ha/Bohr) +Time for force calculation : 0.093 (sec) +Pressure : 1.0212973975E+00 (GPa) +Maximum stress : 2.7256978004E+00 (GPa) +Time for stress calculation : 0.180 (sec) +MD step time : 5.612 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.399365772678 15.399365772678 15.399365772678 -CHEB_DEGREE: 22 +LATVEC_SCALE: 15.2867313976138 15.2867313976138 15.2867313976138 +CHEB_DEGREE: 30 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.358125 (Bohr) +Mesh spacing : 0.254779 (Bohr) =================================================================== - Self Consistent Field (SCF#34) + Self Consistent Field (SCF#24) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462183222E+00 1.871E-03 0.124 -2 -3.2462205930E+00 2.227E-04 0.121 -3 -3.2462206316E+00 8.909E-05 0.121 -4 -3.2462206342E+00 3.160E-05 0.119 -5 -3.2462206345E+00 1.284E-05 0.117 -6 -3.2462206351E+00 5.728E-06 0.115 -7 -3.2462206350E+00 2.225E-06 0.115 -8 -3.2462206344E+00 5.243E-07 0.115 -9 -3.2462206347E+00 2.989E-07 0.128 -Total number of SCF: 9 +1 -3.2459865577E+00 1.849E-03 0.589 +2 -3.2459894351E+00 2.492E-04 0.583 +3 -3.2459894813E+00 1.517E-04 0.586 +4 -3.2459894812E+00 6.150E-05 0.552 +5 -3.2459894822E+00 2.330E-05 0.575 +6 -3.2459894825E+00 5.308E-06 0.573 +7 -3.2459894827E+00 3.633E-06 0.568 +8 -3.2459894824E+00 1.592E-06 0.571 +9 -3.2459894822E+00 5.285E-07 0.558 +10 -3.2459894824E+00 1.241E-07 0.553 +Total number of SCF: 10 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2462206347E+00 (Ha/atom) -Total free energy : -1.0387906031E+02 (Ha) -Band structure energy : 4.0083375353E+00 (Ha) -Exchange correlation energy : -4.1651555873E+01 (Ha) -Self and correction energy : -1.6501141561E+02 (Ha) --Entropy*kb*T : -2.3521375526E-02 (Ha) -Fermi level : 1.9367096514E-01 (Ha) -RMS force : 1.3463858003E-02 (Ha/Bohr) -Maximum force : 2.8234295493E-02 (Ha/Bohr) -Time for force calculation : 0.066 (sec) -Pressure : 2.6626763029E-01 (GPa) -Maximum stress : 1.7765350693E+00 (GPa) -Time for stress calculation : 0.118 (sec) -MD step time : 1.309 (sec) +Free energy per atom : -3.2459894824E+00 (Ha/atom) +Total free energy : -1.0387166344E+02 (Ha) +Band structure energy : 4.7050783559E+00 (Ha) +Exchange correlation energy : -4.1770209222E+01 (Ha) +Self and correction energy : -1.6501194048E+02 (Ha) +-Entropy*kb*T : -2.7243924508E-02 (Ha) +Fermi level : 2.0058513515E-01 (Ha) +RMS force : 1.2697210010E-02 (Ha/Bohr) +Maximum force : 2.5220375784E-02 (Ha/Bohr) +Time for force calculation : 0.093 (sec) +Pressure : 8.1910047397E-01 (GPa) +Maximum stress : 2.4833290892E+00 (GPa) +Time for stress calculation : 0.180 (sec) +MD step time : 6.111 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.4184304955213 15.4184304955213 15.4184304955213 -CHEB_DEGREE: 22 +LATVEC_SCALE: 15.3072173496398 15.3072173496398 15.3072173496398 +CHEB_DEGREE: 30 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.358568 (Bohr) +Mesh spacing : 0.25512 (Bohr) =================================================================== - Self Consistent Field (SCF#35) + Self Consistent Field (SCF#25) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462430661E+00 1.894E-03 0.124 -2 -3.2462453512E+00 2.353E-04 0.121 -3 -3.2462453898E+00 1.186E-04 0.119 -4 -3.2462453909E+00 4.573E-05 0.118 -5 -3.2462453912E+00 1.982E-05 0.123 -6 -3.2462453912E+00 4.531E-06 0.116 -7 -3.2462453913E+00 2.812E-06 0.114 -8 -3.2462453909E+00 1.173E-06 0.114 -9 -3.2462453910E+00 3.130E-07 0.113 -Total number of SCF: 9 +1 -3.2375238788E+00 9.634E-01 0.627 +2 -3.2462169710E+00 6.813E-02 0.617 +3 -3.2461105298E+00 2.492E-02 0.610 +4 -3.2460396993E+00 1.091E-02 0.606 +5 -3.2460232296E+00 2.340E-03 0.590 +6 -3.2460229410E+00 7.040E-04 0.600 +7 -3.2460229528E+00 2.497E-04 0.591 +8 -3.2460229667E+00 1.047E-04 0.593 +9 -3.2460229706E+00 3.399E-05 0.587 +10 -3.2460229718E+00 1.246E-05 0.582 +11 -3.2460229718E+00 6.347E-06 0.583 +12 -3.2460229719E+00 2.265E-06 0.580 +13 -3.2460229721E+00 4.403E-07 0.570 +Total number of SCF: 13 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2462453910E+00 (Ha/atom) -Total free energy : -1.0387985251E+02 (Ha) -Band structure energy : 3.8983137052E+00 (Ha) -Exchange correlation energy : -4.1628567759E+01 (Ha) -Self and correction energy : -1.6501140829E+02 (Ha) --Entropy*kb*T : -2.3345479639E-02 (Ha) -Fermi level : 1.9252436011E-01 (Ha) -RMS force : 1.3494940816E-02 (Ha/Bohr) -Maximum force : 2.8620192053E-02 (Ha/Bohr) -Time for force calculation : 0.064 (sec) -Pressure : 1.3767420035E-01 (GPa) -Maximum stress : 1.6331766039E+00 (GPa) -Time for stress calculation : 0.122 (sec) -MD step time : 1.299 (sec) +Free energy per atom : -3.2460229721E+00 (Ha/atom) +Total free energy : -1.0387273511E+02 (Ha) +Band structure energy : 4.5907376145E+00 (Ha) +Exchange correlation energy : -4.1741737514E+01 (Ha) +Self and correction energy : -1.6501193527E+02 (Ha) +-Entropy*kb*T : -2.6695129406E-02 (Ha) +Fermi level : 1.9940211643E-01 (Ha) +RMS force : 1.2800225045E-02 (Ha/Bohr) +Maximum force : 2.5546510313E-02 (Ha/Bohr) +Time for force calculation : 0.093 (sec) +Pressure : 6.1750135388E-01 (GPa) +Maximum stress : 2.2453517341E+00 (GPa) +Time for stress calculation : 0.182 (sec) +MD step time : 8.180 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.4375201852041 15.4375201852041 15.4375201852041 -CHEB_DEGREE: 22 +LATVEC_SCALE: 15.3280152845433 15.3280152845433 15.3280152845433 +CHEB_DEGREE: 30 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.359012 (Bohr) +Mesh spacing : 0.255467 (Bohr) =================================================================== - Self Consistent Field (SCF#36) + Self Consistent Field (SCF#26) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462657425E+00 1.893E-03 0.126 -2 -3.2462680682E+00 2.267E-04 0.120 -3 -3.2462681070E+00 9.395E-05 0.121 -4 -3.2462681094E+00 3.354E-05 0.118 -5 -3.2462681098E+00 1.553E-05 0.117 -6 -3.2462681100E+00 5.905E-06 0.136 -7 -3.2462681103E+00 2.421E-06 0.119 -8 -3.2462681101E+00 7.592E-07 0.121 -9 -3.2462681101E+00 2.181E-07 0.119 +1 -3.2460524390E+00 1.163E-03 0.606 +2 -3.2460540567E+00 2.229E-04 0.592 +3 -3.2460541014E+00 9.272E-05 0.584 +4 -3.2460541055E+00 3.863E-05 0.580 +5 -3.2460541064E+00 1.842E-05 0.584 +6 -3.2460541064E+00 6.701E-06 0.581 +7 -3.2460541068E+00 3.206E-06 0.580 +8 -3.2460541067E+00 1.010E-06 0.563 +9 -3.2460541064E+00 3.641E-07 0.563 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2462681101E+00 (Ha/atom) -Total free energy : -1.0388057952E+02 (Ha) -Band structure energy : 3.7881967310E+00 (Ha) -Exchange correlation energy : -4.1605906716E+01 (Ha) -Self and correction energy : -1.6501140090E+02 (Ha) --Entropy*kb*T : -2.3222218288E-02 (Ha) -Fermi level : 1.9137255776E-01 (Ha) -RMS force : 1.3523182269E-02 (Ha/Bohr) -Maximum force : 2.9143967065E-02 (Ha/Bohr) -Time for force calculation : 0.065 (sec) -Pressure : 1.6109144155E-02 (GPa) -Maximum stress : 1.6450849968E+00 (GPa) -Time for stress calculation : 0.119 (sec) -MD step time : 1.331 (sec) +Free energy per atom : -3.2460541064E+00 (Ha/atom) +Total free energy : -1.0387373140E+02 (Ha) +Band structure energy : 4.4747278395E+00 (Ha) +Exchange correlation energy : -4.1713112570E+01 (Ha) +Self and correction energy : -1.6501192980E+02 (Ha) +-Entropy*kb*T : -2.6184909982E-02 (Ha) +Fermi level : 1.9820008269E-01 (Ha) +RMS force : 1.2892115296E-02 (Ha/Bohr) +Maximum force : 2.5838966840E-02 (Ha/Bohr) +Time for force calculation : 0.093 (sec) +Pressure : 4.1761289964E-01 (GPa) +Maximum stress : 2.0124409372E+00 (GPa) +Time for stress calculation : 0.183 (sec) +MD step time : 5.634 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.4566003463409 15.4566003463409 15.4566003463409 -CHEB_DEGREE: 22 +LATVEC_SCALE: 15.3490805549791 15.3490805549791 15.3490805549791 +CHEB_DEGREE: 30 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.359456 (Bohr) +Mesh spacing : 0.255818 (Bohr) =================================================================== - Self Consistent Field (SCF#37) + Self Consistent Field (SCF#27) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2462867289E+00 1.886E-03 0.124 -2 -3.2462890350E+00 2.343E-04 0.120 -3 -3.2462890738E+00 1.025E-04 0.119 -4 -3.2462890757E+00 3.972E-05 0.119 -5 -3.2462890763E+00 1.930E-05 0.118 -6 -3.2462890759E+00 5.315E-06 0.117 -7 -3.2462890765E+00 2.532E-06 0.115 -8 -3.2462890763E+00 9.401E-07 0.114 -9 -3.2462890762E+00 2.690E-07 0.112 +1 -3.2460812972E+00 1.138E-03 0.600 +2 -3.2460829159E+00 2.186E-04 0.588 +3 -3.2460829602E+00 9.354E-05 0.579 +4 -3.2460829644E+00 4.131E-05 0.585 +5 -3.2460829648E+00 2.353E-05 0.572 +6 -3.2460829651E+00 6.859E-06 0.577 +7 -3.2460829653E+00 3.262E-06 0.555 +8 -3.2460829653E+00 9.981E-07 0.567 +9 -3.2460829652E+00 3.522E-07 0.543 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2462890762E+00 (Ha/atom) -Total free energy : -1.0388125044E+02 (Ha) -Band structure energy : 3.6781703417E+00 (Ha) -Exchange correlation energy : -4.1583636417E+01 (Ha) -Self and correction energy : -1.6501139329E+02 (Ha) --Entropy*kb*T : -2.3150288822E-02 (Ha) -Fermi level : 1.9021777113E-01 (Ha) -RMS force : 1.3550237037E-02 (Ha/Bohr) -Maximum force : 2.9625486206E-02 (Ha/Bohr) -Time for force calculation : 0.065 (sec) -Pressure : -9.7818430819E-02 (GPa) -Maximum stress : 1.6545438891E+00 (GPa) -Time for stress calculation : 0.120 (sec) -MD step time : 1.295 (sec) +Free energy per atom : -3.2460829652E+00 (Ha/atom) +Total free energy : -1.0387465489E+02 (Ha) +Band structure energy : 4.3573013242E+00 (Ha) +Exchange correlation energy : -4.1684417521E+01 (Ha) +Self and correction energy : -1.6501192443E+02 (Ha) +-Entropy*kb*T : -2.5716481575E-02 (Ha) +Fermi level : 1.9698089866E-01 (Ha) +RMS force : 1.2973204582E-02 (Ha/Bohr) +Maximum force : 2.6097866554E-02 (Ha/Bohr) +Time for force calculation : 0.093 (sec) +Pressure : 2.2062385611E-01 (GPa) +Maximum stress : 1.7853107348E+00 (GPa) +Time for stress calculation : 0.183 (sec) +MD step time : 5.544 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.4756418603131 15.4756418603131 15.4756418603131 -CHEB_DEGREE: 22 +LATVEC_SCALE: 15.3703650594175 15.3703650594175 15.3703650594175 +CHEB_DEGREE: 30 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.359899 (Bohr) +Mesh spacing : 0.256173 (Bohr) =================================================================== - Self Consistent Field (SCF#38) + Self Consistent Field (SCF#28) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2463061285E+00 1.871E-03 0.125 -2 -3.2463084451E+00 2.254E-04 0.120 -3 -3.2463084845E+00 1.032E-04 0.120 -4 -3.2463084865E+00 4.000E-05 0.119 -5 -3.2463084869E+00 1.998E-05 0.117 -6 -3.2463084867E+00 4.742E-06 0.116 -7 -3.2463084870E+00 2.362E-06 0.115 -8 -3.2463084868E+00 8.547E-07 0.114 -9 -3.2463084872E+00 2.823E-07 0.113 +1 -3.2461065988E+00 1.886E-03 0.604 +2 -3.2461096384E+00 2.322E-04 0.583 +3 -3.2461096846E+00 9.517E-05 0.588 +4 -3.2461096890E+00 3.680E-05 0.582 +5 -3.2461096893E+00 1.561E-05 0.580 +6 -3.2461096894E+00 7.043E-06 0.576 +7 -3.2461096901E+00 3.199E-06 0.574 +8 -3.2461096899E+00 8.645E-07 0.574 +9 -3.2461096899E+00 2.566E-07 0.562 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2463084872E+00 (Ha/atom) -Total free energy : -1.0388187159E+02 (Ha) -Band structure energy : 3.5683933585E+00 (Ha) -Exchange correlation energy : -4.1561807902E+01 (Ha) -Self and correction energy : -1.6501138571E+02 (Ha) --Entropy*kb*T : -2.3127427140E-02 (Ha) -Fermi level : 1.8906214635E-01 (Ha) -RMS force : 1.3577771406E-02 (Ha/Bohr) -Maximum force : 3.0063144578E-02 (Ha/Bohr) -Time for force calculation : 0.064 (sec) -Pressure : -2.0368945147E-01 (GPa) -Maximum stress : 1.6616707013E+00 (GPa) -Time for stress calculation : 0.119 (sec) -MD step time : 1.291 (sec) +Free energy per atom : -3.2461096899E+00 (Ha/atom) +Total free energy : -1.0387551008E+02 (Ha) +Band structure energy : 4.2387155569E+00 (Ha) +Exchange correlation energy : -4.1655740340E+01 (Ha) +Self and correction energy : -1.6501191973E+02 (Ha) +-Entropy*kb*T : -2.5292912635E-02 (Ha) +Fermi level : 1.9574653515E-01 (Ha) +RMS force : 1.3044256402E-02 (Ha/Bohr) +Maximum force : 2.6323466498E-02 (Ha/Bohr) +Time for force calculation : 0.093 (sec) +Pressure : 2.7618278969E-02 (GPa) +Maximum stress : 1.8235837979E+00 (GPa) +Time for stress calculation : 0.181 (sec) +MD step time : 5.598 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.4946224878523 15.4946224878523 15.4946224878523 -CHEB_DEGREE: 22 +LATVEC_SCALE: 15.3918192556019 15.3918192556019 15.3918192556019 +CHEB_DEGREE: 30 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.36034 (Bohr) +Mesh spacing : 0.25653 (Bohr) =================================================================== - Self Consistent Field (SCF#39) + Self Consistent Field (SCF#29) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2463240851E+00 1.887E-03 0.124 -2 -3.2463264391E+00 2.388E-04 0.120 -3 -3.2463264780E+00 1.008E-04 0.119 -4 -3.2463264801E+00 3.683E-05 0.121 -5 -3.2463264806E+00 1.824E-05 0.117 -6 -3.2463264805E+00 5.587E-06 0.117 -7 -3.2463264809E+00 2.591E-06 0.115 -8 -3.2463264808E+00 8.932E-07 0.114 -9 -3.2463264808E+00 2.204E-07 0.111 +1 -3.2461311999E+00 1.900E-03 0.592 +2 -3.2461343408E+00 2.292E-04 0.585 +3 -3.2461343874E+00 1.042E-04 0.586 +4 -3.2461343913E+00 4.403E-05 0.574 +5 -3.2461343916E+00 2.326E-05 0.581 +6 -3.2461343918E+00 6.389E-06 0.577 +7 -3.2461343922E+00 3.668E-06 0.566 +8 -3.2461343921E+00 1.351E-06 0.559 +9 -3.2461343916E+00 4.035E-07 0.562 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2463264808E+00 (Ha/atom) -Total free energy : -1.0388244739E+02 (Ha) -Band structure energy : 3.4589924216E+00 (Ha) -Exchange correlation energy : -4.1540453913E+01 (Ha) -Self and correction energy : -1.6501137848E+02 (Ha) --Entropy*kb*T : -2.3150467187E-02 (Ha) -Fermi level : 1.8790756845E-01 (Ha) -RMS force : 1.3607346808E-02 (Ha/Bohr) -Maximum force : 3.0455071829E-02 (Ha/Bohr) -Time for force calculation : 0.065 (sec) -Pressure : -3.0139256385E-01 (GPa) -Maximum stress : 1.6665857892E+00 (GPa) -Time for stress calculation : 0.124 (sec) -MD step time : 1.298 (sec) +Free energy per atom : -3.2461343916E+00 (Ha/atom) +Total free energy : -1.0387630053E+02 (Ha) +Band structure energy : 4.1192362521E+00 (Ha) +Exchange correlation energy : -4.1627173149E+01 (Ha) +Self and correction energy : -1.6501191538E+02 (Ha) +-Entropy*kb*T : -2.4917059539E-02 (Ha) +Fermi level : 1.9449914448E-01 (Ha) +RMS force : 1.3106094597E-02 (Ha/Bohr) +Maximum force : 2.6516025043E-02 (Ha/Bohr) +Time for force calculation : 0.086 (sec) +Pressure : -1.6027084073E-01 (GPa) +Maximum stress : 1.9103141013E+00 (GPa) +Time for stress calculation : 0.166 (sec) +MD step time : 5.547 (sec) *************************************************************************** Reinitialized parameters *************************************************************************** -LATVEC_SCALE: 15.5135243128359 15.5135243128359 15.5135243128359 -CHEB_DEGREE: 22 +LATVEC_SCALE: 15.4133965987445 15.4133965987445 15.4133965987445 +CHEB_DEGREE: 30 *************************************************************************** Reinitialization *************************************************************************** -Mesh spacing : 0.36078 (Bohr) +Mesh spacing : 0.25689 (Bohr) =================================================================== - Self Consistent Field (SCF#40) + Self Consistent Field (SCF#30) =================================================================== Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2463407757E+00 1.865E-03 0.125 -2 -3.2463431206E+00 2.261E-04 0.120 -3 -3.2463431600E+00 9.336E-05 0.120 -4 -3.2463431625E+00 3.305E-05 0.118 -5 -3.2463431629E+00 1.345E-05 0.117 -6 -3.2463431628E+00 4.805E-06 0.116 -7 -3.2463431631E+00 2.038E-06 0.114 -8 -3.2463431628E+00 6.886E-07 0.112 -9 -3.2463431632E+00 2.734E-07 0.137 +1 -3.2461538023E+00 1.940E-03 0.602 +2 -3.2461570438E+00 2.366E-04 0.580 +3 -3.2461570902E+00 9.776E-05 0.587 +4 -3.2461570942E+00 3.850E-05 0.575 +5 -3.2461570944E+00 1.915E-05 0.585 +6 -3.2461570948E+00 8.046E-06 0.576 +7 -3.2461570951E+00 3.522E-06 0.557 +8 -3.2461570951E+00 9.569E-07 0.571 +9 -3.2461570950E+00 2.850E-07 0.556 Total number of SCF: 9 ==================================================================== Energy and force calculation ==================================================================== -Free energy per atom : -3.2463431632E+00 (Ha/atom) -Total free energy : -1.0388298122E+02 (Ha) -Band structure energy : 3.3500757740E+00 (Ha) -Exchange correlation energy : -4.1519596789E+01 (Ha) -Self and correction energy : -1.6501137131E+02 (Ha) --Entropy*kb*T : -2.3215419087E-02 (Ha) -Fermi level : 1.8675587377E-01 (Ha) -RMS force : 1.3640376113E-02 (Ha/Bohr) -Maximum force : 3.0799522256E-02 (Ha/Bohr) -Time for force calculation : 0.384 (sec) -Pressure : -3.9099139394E-01 (GPa) -Maximum stress : 1.6694460835E+00 (GPa) -Time for stress calculation : 0.348 (sec) -MD step time : 1.936 (sec) +Free energy per atom : -3.2461570950E+00 (Ha/atom) +Total free energy : -1.0387702704E+02 (Ha) +Band structure energy : 3.9991192792E+00 (Ha) +Exchange correlation energy : -4.1598802948E+01 (Ha) +Self and correction energy : -1.6501191147E+02 (Ha) +-Entropy*kb*T : -2.4591478689E-02 (Ha) +Fermi level : 1.9324082006E-01 (Ha) +RMS force : 1.3159686811E-02 (Ha/Bohr) +Maximum force : 2.6675299676E-02 (Ha/Bohr) +Time for force calculation : 0.086 (sec) +Pressure : -3.4197565407E-01 (GPa) +Maximum stress : 1.9995632084E+00 (GPa) +Time for stress calculation : 0.167 (sec) *************************************************************************** Timing info *************************************************************************** -Total walltime : 17.185 sec +Total walltime : 74.856 sec ___________________________________________________________________________ *************************************************************************** diff --git a/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.restart b/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.restart index 3923abee..42e05b36 100644 --- a/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.restart +++ b/tests/Al16Si16_NPTNP_restart/standard/Al16Si16_NPTNP_restart.restart @@ -1,81 +1,132 @@ -:MDSTEP: 30 +:MDSTEP: 20 :R(Bohr): - 3.6120769897E-01 3.9317085167E-01 2.2867950980E-01 - 3.8877728998E+00 1.5292220902E+01 4.0899701582E+00 - 7.9696114472E+00 1.5135939674E+01 1.1097530692E-01 - 1.1340682528E+01 1.5296028161E+01 3.6197149122E+00 - 1.4993872519E-01 7.8947833331E+00 1.5301177253E+01 - 3.7258402024E+00 7.8911692518E+00 3.7988950316E+00 - 7.2637456045E+00 7.3964699750E+00 1.5150052913E-01 - 1.1504919160E+01 7.7623127682E+00 4.0247713665E+00 - 5.6082198546E-01 1.5120364182E+01 7.7222062190E+00 - 3.6330380446E+00 3.2134592392E-02 1.1200392685E+01 - 7.6769658828E+00 4.9152500503E-02 7.7898526685E+00 - 1.1558111670E+01 1.5125284029E+01 1.1727978355E+01 - 2.9069358211E-01 7.6817226886E+00 7.8612199041E+00 - 4.2171723953E+00 7.8648785205E+00 1.1457650079E+01 - 7.3034647061E+00 7.9858402672E+00 7.5154678782E+00 - 1.1506356288E+01 7.2480914413E+00 1.1463274360E+01 - 9.2351350990E-02 3.9220706584E+00 3.9277178144E+00 - 3.7104661706E+00 3.8592521142E+00 1.0696516851E-02 - 7.8256576260E+00 3.6238907533E+00 3.4063802372E+00 - 1.1344321889E+01 3.8024412073E+00 1.5164036487E+01 - 3.3509794581E-01 1.1399163620E+01 3.9089049236E+00 - 3.6067147244E+00 1.1538774284E+01 4.9390855581E-01 - 7.8238447845E+00 1.1670810029E+01 3.8375755438E+00 - 1.1017574921E+01 1.1480651023E+01 7.5921931343E-02 - 1.4248082818E-01 3.6977067482E+00 1.1213275946E+01 - 3.8086687480E+00 3.6877017157E+00 7.9525271672E+00 - 7.9090209069E+00 3.7600974033E+00 1.1512603725E+01 - 1.1338447542E+01 3.9571005515E+00 7.8096128199E+00 - 3.0199738312E-01 1.1500733191E+01 1.1483221375E+01 - 3.6777605257E+00 1.1218705341E+01 7.8193731285E+00 - 7.8382874678E+00 1.1721475531E+01 1.1683617103E+01 - 1.1602978167E+01 1.1508310339E+01 7.8150444651E+00 + 3.7831751173E-01 2.7557410771E-01 1.5848196464E-01 + 3.8307019399E+00 1.5185272061E+01 3.9857855576E+00 + 7.8280918133E+00 1.5075872168E+01 1.7588105057E-01 + 1.1293823858E+01 1.5190005016E+01 3.6486358936E+00 + 1.0415135073E-01 7.7713669272E+00 1.5193405045E+01 + 3.7324470235E+00 7.7628177202E+00 3.7785584209E+00 + 7.3198748184E+00 7.4175363575E+00 1.0263692809E-01 + 1.1415544017E+01 7.6740825495E+00 3.9385455216E+00 + 5.3209306376E-01 1.5067160652E+01 7.6521441620E+00 + 3.6535114566E+00 2.2793955436E-02 1.1191959258E+01 + 7.6124803332E+00 3.4779647018E-02 7.7856252630E+00 + 1.1446222187E+01 1.5069776342E+01 1.1568714357E+01 + 2.0136669992E-01 7.6160935305E+00 7.7413291235E+00 + 4.0757260493E+00 7.7499904251E+00 1.1382142238E+01 + 7.3500911393E+00 7.8331274368E+00 7.5018172123E+00 + 1.1418907681E+01 7.3202601330E+00 1.1384034308E+01 + 5.8123667677E-02 3.8679209456E+00 3.8703733184E+00 + 3.7229355180E+00 3.8212161310E+00 1.5204097185E+01 + 7.7131925852E+00 3.6606217154E+00 3.5230047856E+00 + 1.1318458711E+01 3.7740588202E+00 1.5097854782E+01 + 3.0428010409E-01 1.1343514057E+01 3.8578407290E+00 + 3.6497967126E+00 1.1438979423E+01 4.8048939848E-01 + 7.7088133463E+00 1.1530665264E+01 3.8254313409E+00 + 1.1100831196E+01 1.1393952021E+01 4.2414574372E-02 + 9.4960523666E-02 3.7069589955E+00 1.1223806481E+01 + 3.7964961727E+00 3.7033629933E+00 7.7923875869E+00 + 7.7618199903E+00 3.7507178690E+00 1.1425138396E+01 + 1.1301817085E+01 3.8912433990E+00 7.6992407028E+00 + 2.8983493010E-01 1.1409064949E+01 1.1414886556E+01 + 3.7185016263E+00 1.1216447047E+01 7.8659557459E+00 + 7.7072214016E+00 1.1564857746E+01 1.1550324215E+01 + 1.1489857640E+01 1.1417036675E+01 7.6961840612E+00 :V(Bohr/atu): - -9.1529388369E-05 4.9937895022E-04 3.0227568680E-04 - 1.4522732637E-04 -3.5091176190E-05 3.1482675405E-04 - 3.2913872033E-04 -2.2984177783E-04 -3.0647417203E-04 - -1.5203444819E-04 -4.2547139390E-05 -2.3112073250E-04 - 1.9470432371E-04 2.7192298691E-04 -3.3206997879E-05 - -1.6096894699E-04 3.0958107476E-04 -3.4857064423E-05 - -4.7128991859E-04 -3.3172117415E-04 2.1219609575E-04 - 1.3526893442E-05 1.3517967390E-04 2.4772134530E-04 - 6.2379064867E-05 -2.6928657145E-04 3.4942101255E-05 - -1.8391317213E-04 3.3170015120E-05 -3.0312471259E-04 - 3.3464241271E-05 6.2943162925E-05 -2.3647055374E-04 - 1.2554901624E-04 -2.5830542977E-04 3.1200071857E-04 - 3.7935707751E-04 3.9473550246E-05 2.7117899474E-04 - 4.7667016416E-04 2.3700699101E-04 -4.3290006885E-05 - -4.3148896368E-04 3.9986709812E-04 -1.9313325110E-04 - 1.2646696361E-06 -5.6406220843E-04 -2.5664324187E-05 - 1.6808253647E-04 1.0601069167E-04 1.1870001333E-04 - -1.9063493691E-04 4.1476732747E-05 8.9350946697E-05 - 2.4116162714E-04 -2.9142460124E-04 -6.5864933786E-04 - -2.9741723197E-04 2.0470500794E-05 -2.0988204788E-04 - 1.6507633544E-04 -1.3971668409E-04 1.0017644346E-04 - -3.1150650482E-04 5.8485245470E-05 7.2848822450E-05 - 2.5558564490E-04 2.2920129072E-04 -1.0497049798E-04 - -7.7590596399E-04 5.0854361930E-06 1.5741260180E-04 - 2.1046518603E-04 -1.5736582854E-04 -4.4483553893E-04 - -9.3041027145E-05 -1.9373532209E-04 4.6185996582E-04 - 4.1674167033E-04 -8.0574459774E-05 -3.9934246216E-06 - -2.2054761070E-04 1.5443480548E-04 2.5103991351E-04 - 6.2898520017E-05 3.2833790569E-05 -1.0545438385E-04 - -3.5290926518E-04 -3.5722882203E-04 -4.7319045606E-04 - 3.5427447074E-04 3.0575718755E-04 1.8512657564E-04 - 1.0823043398E-04 1.8745804259E-05 2.8796819961E-04 + -8.1269682541E-05 5.3161543648E-04 3.1105244889E-04 + 9.7905425108E-05 -3.8782151341E-05 3.4792877399E-04 + 4.0705051098E-04 -2.5280955808E-04 -2.8016888068E-04 + -1.9597380196E-04 -3.7789375207E-05 -2.7512259002E-04 + 2.0574982720E-04 3.0669509137E-04 -3.2492968734E-05 + -1.4750953894E-04 3.1190200787E-04 -4.0484177560E-05 + -5.2906081678E-04 -3.5816239337E-04 2.1350070981E-04 + 1.3322104168E-05 1.3324170842E-04 2.5909810087E-04 + 1.7053497233E-04 -2.7425562528E-04 7.4921184542E-05 + -2.5038603454E-04 4.7080197264E-05 -3.8305310263E-04 + 2.4467238474E-05 6.4910499289E-05 -2.4878912072E-04 + 9.6304988809E-05 -2.6627128404E-04 3.2554540496E-04 + 4.0079959498E-04 3.0650230556E-05 2.7309899766E-04 + 5.1452984944E-04 2.6689109575E-04 -5.2132672724E-05 + -4.8357030598E-04 4.3418911529E-04 -1.9342773599E-04 + 1.0744262459E-05 -5.7120151055E-04 -3.7279672957E-05 + 1.3124221271E-04 1.1743245578E-04 1.3244957208E-04 + -1.6946422301E-04 3.9261245522E-05 4.1265386096E-05 + 2.3664721018E-04 -2.8203991799E-04 -6.0943112413E-04 + -2.2897697408E-04 -2.5516093513E-05 -2.2074577190E-04 + 8.1100173440E-05 -1.3100389002E-04 9.4894912179E-05 + -3.1699367463E-04 5.7737286514E-05 1.0262216665E-05 + 2.4357625687E-04 2.4042534846E-04 -3.6627274746E-05 + -7.0138348181E-04 -4.7212579133E-06 1.3198857499E-04 + 2.0208629723E-04 -1.7671397048E-04 -4.0009567758E-04 + -4.8840643268E-05 -1.9604846479E-04 4.2897676728E-04 + 3.6280821175E-04 -9.0852953214E-05 1.4978510794E-05 + -2.1496243747E-04 1.7098840155E-04 2.0778007651E-04 + 2.0839930613E-05 1.3271689562E-05 -4.9990274544E-05 + -2.5287028840E-04 -3.7951712446E-04 -4.7112868571E-04 + 2.8322651362E-04 3.1012536219E-04 2.2814220847E-04 + 1.2829180009E-04 2.2151747885E-05 2.4538753182E-04 +:Pm_ion: + -6.1095456032E+01 3.9964826378E+02 2.3383739940E+02 + 7.3601574510E+01 -2.9154946199E+01 2.6155961792E+02 + 3.0600509093E+02 -1.9005260950E+02 -2.1062030755E+02 + -1.4732564995E+02 -2.8408614864E+01 -2.0682669818E+02 + 1.5467489386E+02 2.3056170375E+02 -2.4426977940E+01 + -1.1089206047E+02 2.3447606552E+02 -3.0434464769E+01 + -3.9772779786E+02 -2.6925286371E+02 1.6050171258E+02 + 1.0015051173E+01 1.0016604819E+02 1.9478009677E+02 + 1.2820170546E+02 -2.0617494706E+02 5.6322896717E+01 + -1.8823069669E+02 3.5393101486E+01 -2.8796475214E+02 + 1.8393539210E+01 4.8797244327E+01 -1.8703019762E+02 + 7.2398427378E+01 -2.0017262303E+02 2.4473265249E+02 + 3.0130589006E+02 2.3041677471E+01 2.0530543841E+02 + 3.8680396934E+02 2.0063857390E+02 -3.9191360353E+01 + -3.6352976219E+02 3.2640686137E+02 -1.4541161439E+02 + 8.0771278308E+00 -4.2940756851E+02 -2.8025440100E+01 + 1.0269791107E+02 9.1891683714E+01 1.0364267787E+02 + -1.3260689030E+02 3.0722187762E+01 3.2290441193E+01 + 1.8517802805E+02 -2.2069812614E+02 -4.7688393922E+02 + -1.7917601689E+02 -1.9966514190E+01 -1.7273504602E+02 + 6.3461429274E+01 -1.0251142197E+02 7.4255904793E+01 + -2.4804967499E+02 4.5179813670E+01 8.0302533204E+00 + 1.9060005352E+02 1.8813444657E+02 -2.8661087975E+01 + -5.4883727539E+02 -3.6944159604E+00 1.0328194456E+02 + 1.5813388203E+02 -1.3827986629E+02 -3.1307754926E+02 + -3.8218130702E+01 -1.5340923767E+02 3.3567719553E+02 + 2.8389985734E+02 -7.1093044813E+01 1.1720785087E+01 + -1.6820954806E+02 1.3379957022E+02 1.6258930247E+02 + 1.6307385380E+01 1.0385186033E+01 -3.9117724880E+01 + -1.9787269548E+02 -2.9697469352E+02 -3.6866135421E+02 + 2.2162664517E+02 2.4267517446E+02 1.7852280721E+02 + 1.0038919342E+02 1.7333891188E+01 1.9201738831E+02 :NPT_NP_QMASS: 500 :NPT_NP_BMASS: 0.1 -:NPT_NP_Sv: 6.90592967649367e-05 -:NPT_NP_Pm: 0.515023200248996 0.515023200248996 0.515023200248996 -:NPT_NP_S: 1.03446317630513 -:NPT_NP_range_x_velo: 0.000740274731460232 -:NPT_NP_range_y_velo: 0.000740274731460232 -:NPT_NP_range_z_velo: 0.000740274731460232 -:LATVEC_SCALE: 15.3240291435853 15.3240291435853 15.3240291435853 +:NPT_NP_SNOSE[0]: 1.00739483002961 +:NPT_NP_SNOSE[1]: 4.09685325782523e-05 +:NPT_NP_SNOSE[2]: 1.00637161793865 +:NPT_NP_INIT_Hamiltonian: -103.681526754895 +:KE: 0.164437543931353 +:Kbaro: 0.0169533277071484 +:Ubaro: 0 +:kinetic_stress: + 0.000273144812634447 -8.96810111238456e-07 3.89087528613967e-06 + -8.96810111238456e-07 0.00020940087218719 4.52668252188278e-05 + 3.89087528613967e-06 4.52668252188278e-05 0.000230064338148921 +:Pm_metric_tensor: + 0.519041658963769 0.000986583332382675 -0.00375003791063987 + 0.000986583332382675 0.502128135055276 0.00041702636950794 + -0.00375003791063987 0.00041702636950794 0.516227485294508 +:LATVEC_SCALE: 1.5208810074E+01 1.5208810074E+01 1.5208810074E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:INITIAL_ANGLES: 9.0000000000E+01 9.0000000000E+01 9.0000000000E+01 +:ROTATION_MATRIX: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 :TTHRMI(K): 1120 -:TARGET_PRESSURE: 0 GPa -:NPT_NP_ini_Hamiltonian: -103.68207963937 -:TEL(K): 1120 -:TIO(K): 1122.49944988328 +:EXTERNAL_PRESSURE: 0 +:EXTERNAL_STRESS: 0 0 0 0 0 0 GPa +:TEL(K): 1.1200000000E+03 +:TIO(K): 1.1166724627E+03 diff --git a/tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.inpt b/tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.inpt new file mode 100644 index 00000000..bf1a1efe --- /dev/null +++ b/tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.inpt @@ -0,0 +1,45 @@ +# nprocs: 48 +LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 +LATVEC: +1 0.0 0.0 +0.0 1.0 0.0 +0.0 0.0 1.0 +MESH_SPACING: 0.15 +BC: P P P +KPOINT_GRID: 1 1 1 +EXCHANGE_CORRELATION: GGA_PBE +TOL_SCF: 1e-6 +# TOL_POISSON: 1e-7 +# TOL_PSEUDOCHARGE: 1e-5 +MIXING_PARAMETER: 1.0 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +PRECOND_KERKER_THRESH: 0 + +# MD +MD_FLAG: 1 # 1 = MD, 0 = no MD (default) +ION_TEMP: 2400 # kelvin +# ION_TEMP_END: 1120 +MD_METHOD: NPH # NVE, NVT_NH (Nose-Hoover), NVK_G (Gaussian) +#QMASS: 1600 # mass for NH thermostat +MD_TIMESTEP: 1 # fs +MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whichever comes first +#TWTIME: 1400 +RESTART_FLAG: 0 # 1 = restart MD from .restart file if present, 0 = start new +#ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) +EXTERNAL_PRESSURE: 0.1 GPa +#EXTERNAL_STRESS: 0 0 0 0 0 0 +#NPT_NP_QMASS: 20000 +NPH_BMASS: 0.5 +NPH_ANGLES: 1 +#NPT_SCALE_CONSTRAINTS: 12 + +NSTATES: 80 + +# outputs +# CALC_PRES: 1 +CALC_STRESS: 1 # whether this selection changes the result of NPT? +PRINT_ATOMS: 1 +# PRINT_VELS: 1 +PRINT_FORCES: 1 +PRINT_MDOUT: 1 # print MD output to .aimd file diff --git a/tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.ion b/tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.ion similarity index 100% rename from tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.ion rename to tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.ion diff --git a/tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.refaimd b/tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.refaimd new file mode 100644 index 00000000..fe43da8c --- /dev/null +++ b/tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.refaimd @@ -0,0 +1,1157 @@ +:Description: + +:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr +:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu + where atu is the atomic unit of time, hbar/Ha +:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr +:Desc_MDTM: MD time. Unit=second +:Desc_TEL: Electronic temperature. Unit=Kelvin +:Desc_TIO: Ionic temperature. Unit=Kelvin +:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom +:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom +:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom + where N = number of particles, k = Boltzmann constant +:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom +:Desc_UEN: Internal energy. Unit=Ha/atom +:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom +:Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree +:Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 +:Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 +:Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during NPH ensemble (has same magnitude as initial LatVec). Unit = Bohr +:Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha +:Desc_NPH_Enthalpy: Enthalpy of the NPH system (or generalized enthalpy in case of anisotropic stress). This quantity is same as NPH Hamiltonian (NPH_HAMIL) plus the initial NPH hamiltonian. Unit = Ha +:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa +:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa +:Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa +:Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa +:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa + where N = number of particles, k = Boltzmann constant, V = volume +:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr + + + + +:MDSTEP: 1 +:MDTM: 245.31 +:TWIST: 0 +:TEL: 2400 +:TIO: 2400.3409911686 +:TEN: -2.6048830089E+00 +:KEN: 1.0832034340E-02 +:KENIG: 1.1402141411E-02 +:FEN: -2.6157150432E+00 +:UEN: -2.6085105501E+00 +:TSEN: -7.2044931125E-03 +:NPH_HAMIL: 3.9729370279E-05 +:NPH_ENTHALPY: -5.2074714107E+01 +:R: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 6.2990803296E+00 + 0.0000000000E+00 0.0000000000E+00 1.2598160659E+01 + 0.0000000000E+00 6.2990803296E+00 0.0000000000E+00 + 0.0000000000E+00 6.2990803296E+00 6.2990803296E+00 + 0.0000000000E+00 6.2990803296E+00 1.2598160659E+01 + 0.0000000000E+00 1.2598160659E+01 0.0000000000E+00 + 0.0000000000E+00 1.2598160659E+01 6.2990803296E+00 + 0.0000000000E+00 1.2598160659E+01 1.2598160659E+01 + 6.2990803296E+00 0.0000000000E+00 0.0000000000E+00 + 6.2990803296E+00 0.0000000000E+00 6.2990803296E+00 + 6.2990803296E+00 0.0000000000E+00 1.2598160659E+01 + 6.2990803296E+00 6.2990803296E+00 0.0000000000E+00 + 6.2990803296E+00 6.2990803296E+00 6.2990803296E+00 + 6.2990803296E+00 6.2990803296E+00 1.2598160659E+01 + 6.2990803296E+00 1.2598160659E+01 0.0000000000E+00 + 6.2990803296E+00 1.2598160659E+01 6.2990803296E+00 + 6.2990803296E+00 1.2598160659E+01 1.2598160659E+01 + 1.2598160659E+01 0.0000000000E+00 0.0000000000E+00 + 1.2598160659E+01 0.0000000000E+00 6.2990803296E+00 +:V: + -6.7508280372E-06 6.8757511080E-04 4.3936259914E-04 + 3.7355675318E-05 -1.5727035159E-04 5.1719530206E-04 + 6.4986379370E-04 -4.5410617361E-04 -3.0784983050E-04 + -3.2394421661E-04 -1.3629701576E-04 -4.4900401974E-04 + 2.9184533862E-04 4.0511688715E-04 -3.3972674996E-05 + -1.6699314049E-04 3.6969182354E-04 -5.9863046606E-05 + -7.8895519107E-04 -5.9299530212E-04 2.6594886664E-04 + 4.8087373181E-05 1.3106945511E-04 3.9308978812E-04 + 4.6023589685E-04 -4.7427995942E-04 1.4680549366E-04 + -4.4621371706E-04 -2.7196363773E-05 -6.1810882096E-04 + 2.1175065594E-05 1.9314810955E-05 -3.0796047744E-04 + 9.2718390730E-05 -4.7512761886E-04 4.3477900781E-04 + 5.4429992079E-04 -4.6900741594E-05 3.8053216026E-04 + 7.8083614038E-04 3.4893052940E-04 -5.1048612828E-05 + -7.0230042056E-04 5.7124856047E-04 -2.9842620412E-04 + 5.5677163530E-05 -8.3790478060E-04 -5.9249895237E-05 + -3.2642486712E-04 5.9659763495E-04 -2.8120765170E-05 + -1.4748610579E-04 9.7055024094E-06 -4.3002558952E-04 + 1.9870161437E-04 1.8287981344E-04 2.9481464826E-04 + -3.6274800256E-04 -4.1742864006E-05 -1.4673917558E-04 +:F: + -3.1866012212E-03 1.5087632637E-07 3.2887839393E-04 + -3.1867956384E-03 1.5507450062E-07 -3.2888132829E-04 + 1.1727404095E-02 1.4193038219E-07 -1.0839888494E-07 + 1.2514148213E-02 -2.4256492503E-04 1.2604851523E-04 + 1.2514273579E-02 -2.4260145018E-04 -1.2590281603E-04 + 1.3273774869E-02 -5.5117805875E-05 -1.6001616369E-07 + 1.2514125671E-02 2.4242057692E-04 1.2603956532E-04 + 1.2514174035E-02 2.4243730040E-04 -1.2588694622E-04 + 1.3273644852E-02 5.4965509367E-05 -1.6930989011E-07 + 3.1913546596E-03 1.5833394905E-07 3.2900129133E-04 + 3.1910354645E-03 1.5572866889E-07 -3.2899609126E-04 + -1.1727613318E-02 1.4373989272E-07 -1.1923646117E-07 + -1.2514174647E-02 -2.4263450198E-04 1.2600913948E-04 + -1.2514302131E-02 -2.4265787221E-04 -1.2586930053E-04 + -1.3273742866E-02 -5.5099181382E-05 -1.5587696919E-07 + -1.2514169191E-02 2.4247111951E-04 1.2600559863E-04 + -1.2514215292E-02 2.4250320516E-04 -1.2584171526E-04 + -1.3273622595E-02 5.4942005995E-05 -1.7309700631E-07 + -4.5802842838E-06 4.6416089303E-08 1.1883378075E-02 + -4.1182543880E-06 -1.6080512923E-08 -1.1883096446E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483330373E+03 +:LATVEC_SCALE: + 1.8897259886E+01 1.8897259886E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0617480575E-01 -7.6076992918E-02 1.3809311380E-01 + -7.6076992918E-02 7.2214979790E-01 -2.9244330457E-02 + 1.3809311380E-01 -2.9244330457E-02 4.6067198607E-01 +:STRESS: + 4.9507436283E+00 -2.4271860853E-07 7.3620867370E-07 + -2.4271860853E-07 5.5272844776E+00 -5.3983401024E-07 + 7.3620867370E-07 -5.3983401024E-07 5.7978356605E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2445688226E+00 -7.6076750199E-02 1.3809237760E-01 + -7.6076750199E-02 -4.8051346797E+00 -2.9243790623E-02 + 1.3809237760E-01 -2.9243790623E-02 -5.3371636745E+00 +:PRESIO: 6.2966552990E-01 +:PRES: -5.4252879222E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7956223923E+00 +:PRESIG: 6.6280582095E-01 +:MIND: +Al - Al: 6.2990803296E+00 +C - C: 6.2990803296E+00 +Al - C: 6.2990803296E+00 + + +:MDSTEP: 2 +:MDTM: 196.65 +:TWIST: 0 +:TEL: 2400 +:TIO: 2403.31158128556 +:TEN: -2.6048863022E+00 +:KEN: 1.0845439741E-02 +:KENIG: 1.1416252359E-02 +:FEN: -2.6157317420E+00 +:UEN: -2.6085326455E+00 +:TSEN: -7.1990964725E-03 +:NPH_HAMIL: 4.4033873941E-05 +:NPH_ENTHALPY: -5.2074709802E+01 +:R: + 1.8896572071E+01 2.8424697262E-02 1.8169142131E-02 + 1.4840797914E-03 1.8890357689E+01 6.3203082637E+00 + 2.7072111134E-02 1.8878084770E+01 1.2585139189E+01 + 1.8883750211E+01 6.2933037845E+00 1.8878257821E+01 + 1.2285837235E-02 6.3156892729E+00 6.2975262824E+00 + 1.8890244378E+01 6.3142264549E+00 1.2595391063E+01 + 1.8864499836E+01 1.2573384163E+01 1.0996623905E-02 + 2.2046379240E-03 1.2603315776E+01 6.3151812183E+00 + 1.9263793025E-02 1.2578285488E+01 1.2603934824E+01 + 6.2805813028E+00 1.8895731853E+01 1.8871270486E+01 + 6.2999008437E+00 7.9690408379E-04 6.2861959869E+00 + 6.3025944501E+00 1.8877215725E+01 1.2615839767E+01 + 6.3212426958E+00 6.2970042188E+00 1.5733543237E-02 + 6.3310286992E+00 6.3133664999E+00 6.2968203568E+00 + 6.2697092189E+00 6.3225589141E+00 1.2585528765E+01 + 6.3010610770E+00 1.2563254730E+01 1.8894370414E+01 + 6.2852497350E+00 1.2622560949E+01 6.2977682038E+00 + 6.2926414611E+00 1.2598293695E+01 1.2580088393E+01 + 1.2606139354E+01 7.5603416465E-03 1.2651556716E-02 + 1.2582923804E+01 1.8895133656E+01 6.2924028685E+00 +:V: + -9.4490378018E-06 6.8791023170E-04 4.3972110947E-04 + 3.4804427205E-05 -1.5742084602E-04 5.1706471837E-04 + 6.5973895928E-04 -4.5425729621E-04 -3.0804298604E-04 + -3.1352236071E-04 -1.3659993113E-04 -4.4897970055E-04 + 3.0232099001E-04 4.0503421855E-04 -3.3984098000E-05 + -1.5574725505E-04 3.6992022939E-04 -5.9834503791E-05 + -7.7857909417E-04 -5.9304606528E-04 2.6606322787E-04 + 5.8693284944E-05 1.3131716193E-04 3.9301143174E-04 + 4.7147030010E-04 -4.7433882656E-04 1.4676198679E-04 + -4.4386788744E-04 -2.7035818266E-05 -6.1807768425E-04 + 2.4040115551E-05 1.9167224829E-05 -3.0830367212E-04 + 8.2864559896E-05 -4.7535697170E-04 4.3505213650E-04 + 5.3387772633E-04 -4.6998049782E-05 3.8077530636E-04 + 7.7040007243E-04 3.4868542318E-04 -5.1149217866E-05 + -7.1356103650E-04 5.7146082576E-04 -2.9861502307E-04 + 4.5256603731E-05 -8.3796220500E-04 -5.9084851311E-05 + -3.3703050473E-04 5.9697121611E-04 -2.8158165024E-05 + -1.5872740789E-04 9.7193166930E-06 -4.3014797383E-04 + 1.9931396619E-04 1.8282644641E-04 3.1756079659E-04 + -3.6326192432E-04 -4.1684623987E-05 -1.6946007579E-04 +:F: + -3.2332249126E-03 7.6271462579E-04 4.9926087961E-04 + -2.8853088746E-03 -3.5040048736E-04 -1.0429586443E-05 + 1.1740670653E-02 -3.3793405172E-04 -4.4022332037E-04 + 1.2298049729E-02 -4.7085034150E-04 -4.4002213862E-05 + 1.2398527078E-02 2.5087871112E-05 1.0121521014E-04 + 1.3492141300E-02 5.8027264662E-04 7.0730993191E-05 + 1.2209882866E-02 -3.3220099332E-04 1.2939996637E-04 + 1.2719417342E-02 3.4028951766E-04 -8.2370570888E-05 + 1.3437041721E-02 -1.7193592521E-04 -1.0992527770E-04 + 2.4101641523E-03 3.8390711223E-04 -2.2174351104E-04 + 3.6251324017E-03 -3.5233117035E-04 -4.7040071196E-04 + -1.1722738225E-02 -5.2213913296E-04 6.2633002394E-04 + -1.2308633608E-02 1.2618285412E-05 4.3289822224E-04 + -1.2352041704E-02 -3.5928669255E-04 -1.0868218649E-04 + -1.3488544148E-02 5.3257467897E-04 -4.3485088744E-04 + -1.2283008210E-02 -3.3709770056E-04 2.7064489649E-04 + -1.2706339109E-02 6.1694522181E-04 3.7124780851E-05 + -1.3467395106E-02 -2.2322167599E-05 -2.6752340045E-04 + 6.4925723270E-04 -6.0801278320E-05 1.2202312013E-02 + -5.3305057779E-04 6.2889981850E-05 -1.2179765319E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7479064500E+03 +:LATVEC_SCALE: + 1.8896906515E+01 1.8896860912E+01 1.8896817639E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -6.5493037756E-07 1.0000000000E+00 0.0000000000E+00 + 1.1888110106E-06 -2.5175382420E-07 1.0000000000E+00 +:STRIO: + 7.0592107598E-01 -7.8716113669E-02 1.3856353685E-01 + -7.8716113669E-02 7.2258726626E-01 -2.8780726284E-02 + 1.3856353685E-01 -2.8780726284E-02 4.6294557893E-01 +:STRESS: + 4.9432461915E+00 -1.6161990473E-03 1.5565422371E-03 + -1.6161990473E-03 5.5300180943E+00 6.0881996247E-04 + 1.5565422371E-03 6.0881996247E-04 5.8015361227E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2373251155E+00 -7.7099914622E-02 1.3700699461E-01 + -7.7099914622E-02 -4.8074308281E+00 -2.9389546246E-02 + 1.3700699461E-01 -2.9389546246E-02 -5.3385905438E+00 +:PRESIO: 6.3048464039E-01 +:PRES: -5.4249334695E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7944488291E+00 +:PRESIG: 6.6366804252E-01 +:MIND: +Al - Al: 6.2554968552E+00 +C - C: 6.2798058496E+00 +Al - C: 6.2830265375E+00 + + +:MDSTEP: 3 +:MDTM: 195.70 +:TWIST: 0 +:TEL: 2400 +:TIO: 2410.22108895319 +:TEN: -2.6048938356E+00 +:KEN: 1.0876620321E-02 +:KENIG: 1.1449074022E-02 +:FEN: -2.6157704560E+00 +:UEN: -2.6085800832E+00 +:TSEN: -7.1903727928E-03 +:NPH_HAMIL: 3.3638847320E-05 +:NPH_ENTHALPY: -5.2074720197E+01 +:R: + 1.8895419104E+01 5.6874681986E-02 3.6354789045E-02 + 2.8628206278E-03 1.8883042768E+01 6.3413873571E+00 + 5.4553481804E-02 1.8858496331E+01 1.2571808034E+01 + 1.8870333589E+01 6.2873732696E+00 1.8858812687E+01 + 2.5005247579E-02 6.3321637247E+00 6.2958283337E+00 + 1.8883355757E+01 6.3292558363E+00 1.2592329104E+01 + 1.8831804161E+01 1.2548330989E+01 2.1997261535E-02 + 4.8502790176E-03 1.2608214741E+01 6.3311310086E+00 + 3.9000332315E-02 1.2558135849E+01 1.2609409909E+01 + 6.2620587611E+00 1.8893813219E+01 1.8844832175E+01 + 6.3007370640E+00 1.5799481351E-03 6.2731484205E+00 + 6.3055859074E+00 1.8856751839E+01 1.2633244839E+01 + 6.3428548026E+00 6.2947955602E+00 3.1481364842E-02 + 6.3624322706E+00 6.3275049344E+00 6.2944091980E+00 + 6.2397634851E+00 6.3459187379E+00 1.2572587431E+01 + 6.3025113200E+00 1.2528067630E+01 1.8891048026E+01 + 6.2708595421E+00 1.2646713891E+01 6.2963099711E+00 + 6.2856236932E+00 1.2598156617E+01 1.2561712723E+01 + 1.2613933238E+01 1.5115613186E-02 2.6254985372E-02 + 1.2567405547E+01 1.8892611597E+01 6.2846275442E+00 +:V: + -1.2188874003E-05 6.8890330707E-04 4.4023471822E-04 + 3.2506278539E-05 -1.5786752805E-04 5.1721322908E-04 + 6.6963487551E-04 -4.5470547287E-04 -3.0861303580E-04 + -3.0329282384E-04 -1.3709473661E-04 -4.4910683395E-04 + 3.1270713786E-04 4.0518354307E-04 -3.3806556925E-05 + -1.4432167503E-04 3.7068922833E-04 -5.9746272380E-05 + -7.6847443781E-04 -5.9359987235E-04 2.6618766001E-04 + 6.9473649181E-05 1.3164918132E-04 3.9297804823E-04 + 4.8284792808E-04 -4.7459605530E-04 1.4662707200E-04 + -4.4218013588E-04 -2.6551979517E-05 -6.1852346248E-04 + 2.7274065861E-05 1.8725705151E-05 -3.0877381435E-04 + 7.3018092291E-05 -4.7603584865E-04 4.3585912357E-04 + 5.2364163520E-04 -4.6880785466E-05 3.8128558610E-04 + 7.6011550383E-04 3.4834893851E-04 -5.1240640880E-05 + -7.2501509671E-04 5.7217991775E-04 -2.9917412110E-04 + 3.5030256297E-05 -8.3852698516E-04 -5.8799662500E-05 + -3.4780172366E-04 5.9766958061E-04 -2.8060142860E-05 + -1.7013327217E-04 9.6718856489E-06 -4.3050276051E-04 + 2.0115349977E-04 1.8266566470E-04 3.4095230273E-04 + -3.6478455418E-04 -4.1506287251E-05 -1.9277541149E-04 +:F: + -3.2850470616E-03 1.5310936101E-03 6.7293640767E-04 + -2.5859492345E-03 -6.9671402922E-04 3.0657775075E-04 + 1.1746807882E-02 -6.8488307550E-04 -8.7753837527E-04 + 1.2069779947E-02 -6.9178477941E-04 -2.1005734099E-04 + 1.2287179207E-02 2.8854277233E-04 3.2625816263E-04 + 1.3707507903E-02 1.2127682974E-03 1.4458070333E-04 + 1.1902161385E-02 -9.2349325926E-04 1.3338474471E-04 + 1.2925949536E-02 4.3631161270E-04 -4.0637501550E-05 + 1.3592736214E-02 -3.9393510107E-04 -2.2417939775E-04 + 1.6450937635E-03 7.7144151640E-04 -7.7255163196E-04 + 4.0675345776E-03 -7.0022334041E-04 -6.1377890787E-04 + -1.1713117465E-02 -1.0456420898E-03 1.2463511739E-03 + -1.2094386062E-02 2.6946728564E-04 7.4187153972E-04 + -1.2187357506E-02 -4.7878542190E-04 -9.9254717034E-05 + -1.3701568753E-02 1.1232479528E-03 -8.6693498003E-04 + -1.2053377592E-02 -9.2264278938E-04 4.1574244515E-04 + -1.2892516669E-02 9.8580765474E-04 1.9659954664E-04 + -1.3657378378E-02 -9.0996465661E-05 -5.2967189200E-04 + 1.2912912377E-03 -1.1795800864E-04 1.2558420630E-02 + -1.0653429310E-03 1.2837765812E-04 -1.2508118360E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7470533759E+03 +:LATVEC_SCALE: + 1.8896200321E+01 1.8896062725E+01 1.8895932970E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.9737893896E-06 1.0000000000E+00 0.0000000000E+00 + 3.5574319418E-06 -7.5658704426E-07 9.9999999999E-01 +:STRIO: + 7.0697375007E-01 -8.1494708379E-02 1.3938231796E-01 + -8.1494708379E-02 7.2410647768E-01 -2.8369034537E-02 + 1.3938231796E-01 -2.8369034537E-02 4.6605144956E-01 +:STRESS: + 4.9344635728E+00 -3.3060993005E-03 2.6015657840E-03 + -3.3060993005E-03 5.5308076369E+00 1.6883201868E-03 + 2.6015657840E-03 1.6883201868E-03 5.8052528594E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2274898228E+00 -7.8188609078E-02 1.3678075217E-01 + -7.8188609078E-02 -4.8067011592E+00 -3.0057354723E-02 + 1.3678075217E-01 -3.0057354723E-02 -5.3392014098E+00 +:PRESIO: 6.3237722577E-01 +:PRES: -5.4235080230E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7911307973E+00 +:PRESIG: 6.6566023765E-01 +:MIND: +Al - Al: 6.2118504009E+00 +C - C: 6.2585873470E+00 +Al - C: 6.2666810427E+00 + + +:MDSTEP: 4 +:MDTM: 146.96 +:TWIST: 0 +:TEL: 2400 +:TIO: 2421.10563491115 +:TEN: -2.6049047023E+00 +:KEN: 1.0925739082E-02 +:KENIG: 1.1500777981E-02 +:FEN: -2.6158304414E+00 +:UEN: -2.6086522125E+00 +:TSEN: -7.1782289081E-03 +:NPH_HAMIL: 2.6495901160E-05 +:NPH_ENTHALPY: -5.2074727340E+01 +:R: + 1.8893799918E+01 8.5376040524E-02 5.4562556069E-02 + 4.1464702490E-03 1.8875303139E+01 6.3623280645E+00 + 8.2443594251E-02 1.8838482820E+01 1.2558152148E+01 + 1.8857002899E+01 6.2812811053E+00 1.8838918996E+01 + 3.8154013620E-02 6.3485124437E+00 6.2939942685E+00 + 1.8876602213E+01 6.3441900364E+00 1.2588977305E+01 + 1.8799163403E+01 1.2522981053E+01 3.3001824235E-02 + 7.9439340301E-03 1.2612860704E+01 6.3469307119E+00 + 5.9214544502E-02 1.2537704351E+01 1.2614581662E+01 + 6.2434864260E+00 1.8891517322E+01 1.8817926270E+01 + 6.3016045360E+00 2.3369986537E-03 6.2599328913E+00 + 6.3080550981E+00 1.8835850329E+01 1.2650396876E+01 + 6.3639239228E+00 6.2924633113E+00 4.7253804909E-02 + 6.3932963389E+00 6.3414911474E+00 6.2918471416E+00 + 6.2092363929E+00 6.3691797234E+00 1.2559321865E+01 + 6.3034391524E+00 1.2492579611E+01 1.8887297644E+01 + 6.2559036324E+00 1.2670631703E+01 6.2947111674E+00 + 6.2780206237E+00 1.2597746934E+01 1.2543024854E+01 + 1.2621592773E+01 2.2661191380E-02 4.0837710543E-02 + 1.2551564890E+01 1.8889698771E+01 6.2757289086E+00 +:V: + -1.4975721024E-05 6.9055728160E-04 4.4090557125E-04 + 3.0458823108E-05 -1.5860642514E-04 5.1763891025E-04 + 6.7954571375E-04 -4.5545792209E-04 -3.0955664692E-04 + -2.9326538652E-04 -1.3777472046E-04 -4.4938206221E-04 + 3.2300781029E-04 4.0556078871E-04 -3.3441864051E-05 + -1.3271858546E-04 3.7199553256E-04 -5.9596028233E-05 + -7.5864300259E-04 -5.9466939382E-04 2.6632226851E-04 + 8.0429863809E-05 1.3206417903E-04 3.9298835317E-04 + 4.9436239107E-04 -4.7504690837E-04 1.4639706734E-04 + -4.4113743231E-04 -2.5742008422E-05 -6.1944465806E-04 + 3.0883112933E-05 1.7994579404E-05 -3.0937197133E-04 + 6.3182095801E-05 -4.7716463972E-04 4.3719279443E-04 + 5.1359802948E-04 -4.6548642085E-05 3.8206442047E-04 + 7.4998360079E-04 3.4791901783E-04 -5.1329171561E-05 + -7.3666066319E-04 5.7340723198E-04 -3.0010079506E-04 + 2.4996256927E-05 -8.3960275137E-04 -5.8393670906E-05 + -3.5873366108E-04 5.9868729688E-04 -2.7830046690E-05 + -1.8170067957E-04 9.5706799384E-06 -4.3108516541E-04 + 2.0420126040E-04 1.8240450874E-04 3.6506094069E-04 + -3.6731829901E-04 -4.1202793261E-05 -2.1674740419E-04 +:F: + -3.3442362866E-03 2.3004987545E-03 8.4831010953E-04 + -2.2900034086E-03 -1.0377351031E-03 6.2038062251E-04 + 1.1745382199E-02 -1.0401012456E-03 -1.3095477934E-03 + 1.1829492682E-02 -9.0405453363E-04 -3.7201483622E-04 + 1.2180129279E-02 5.4646014738E-04 5.4907496798E-04 + 1.3919632305E-02 1.8401663673E-03 2.2104572727E-04 + 1.1592743119E-02 -1.5281626567E-03 1.3704045473E-04 + 1.3133551970E-02 5.3090937719E-04 -1.3096764591E-07 + 1.3739947374E-02 -6.0956108925E-04 -3.4260466335E-04 + 8.9477766599E-04 1.1618717045E-03 -1.3196058271E-03 + 4.5160573912E-03 -1.0423518503E-03 -7.5762657233E-04 + -1.1699967469E-02 -1.5687043145E-03 1.8555199402E-03 + -1.1872722508E-02 5.2543633240E-04 1.0519863464E-03 + -1.2021357476E-02 -6.0025652298E-04 -9.7085958446E-05 + -1.3910786005E-02 1.7141660295E-03 -1.2951586973E-03 + -1.1825758533E-02 -1.5107005870E-03 5.6186032333E-04 + -1.3072128201E-02 1.3472587349E-03 3.5150470682E-04 + -1.3842954246E-02 -1.5043367953E-04 -7.8562551043E-04 + 1.9249384057E-03 -1.7134387756E-04 1.2952186521E-02 + -1.5967382581E-03 1.9663801247E-04 -1.2869508894E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7457741030E+03 +:LATVEC_SCALE: + 1.8895142017E+01 1.8894865282E+01 1.8894605710E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -3.9663538800E-06 9.9999999999E-01 0.0000000000E+00 + 7.1046363976E-06 -1.5204010182E-06 9.9999999997E-01 +:STRIO: + 7.0933257741E-01 -8.4414917828E-02 1.4055936035E-01 + -8.4414917828E-02 7.2671526793E-01 -2.8010504697E-02 + 1.4055936035E-01 -2.8010504697E-02 4.7001266681E-01 +:STRESS: + 4.9244364892E+00 -5.0570342041E-03 3.0829195851E-03 + -5.0570342041E-03 5.5296585292E+00 3.2292223074E-03 + 3.0829195851E-03 3.2292223074E-03 5.8090118778E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2151039118E+00 -7.9357883624E-02 1.3747644077E-01 + -7.9357883624E-02 -4.8029432613E+00 -3.1239727005E-02 + 1.3747644077E-01 -3.1239727005E-02 -5.3389992110E+00 +:PRESIO: 6.3535350405E-01 +:PRES: -5.4210356321E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7856821280E+00 +:PRESIG: 6.6879316216E-01 +:MIND: +Al - Al: 6.1681185755E+00 +C - C: 6.2353752704E+00 +Al - C: 6.2499848919E+00 + + +:MDSTEP: 5 +:MDTM: 157.09 +:TWIST: 0 +:TEL: 2400 +:TIO: 2436.00124009132 +:TEN: -2.6049182488E+00 +:KEN: 1.0992958576E-02 +:KENIG: 1.1571535344E-02 +:FEN: -2.6159112073E+00 +:UEN: -2.6087486641E+00 +:TSEN: -7.1625431830E-03 +:NPH_HAMIL: 3.5374588663E-05 +:NPH_ENTHALPY: -5.2074718461E+01 +:R: + 1.8891713359E+01 1.1395489219E-01 7.2798116663E-02 + 5.3451957355E-03 1.8867127168E+01 6.3831407310E+00 + 1.1074175059E-01 1.8818032342E+01 1.2544156676E+01 + 1.8843750909E+01 6.2750198957E+00 1.8818571410E+01 + 5.1728106583E-02 6.3647440338E+00 6.2920317957E+00 + 1.8869992078E+01 6.3590504485E+00 1.2585338284E+01 + 1.8766568188E+01 1.2497313940E+01 4.4010210404E-02 + 1.1492683677E-02 1.2617256867E+01 6.3625812982E+00 + 7.9911147664E-02 1.2516983901E+01 1.2619445690E+01 + 6.2248387232E+00 1.8888857709E+01 1.8790534225E+01 + 6.3025191215E+00 3.0560961854E-03 6.2465446471E+00 + 6.3100026934E+00 1.8814493453E+01 1.2667316505E+01 + 6.3844576477E+00 6.2900164623E+00 6.3061242515E-02 + 6.4236263571E+00 6.3553206231E+00 6.2891342277E+00 + 6.1781214969E+00 6.3923618086E+00 1.2545717415E+01 + 6.3038528063E+00 1.2456770880E+01 1.8883124233E+01 + 6.2403762187E+00 1.2694326449E+01 6.2929771736E+00 + 6.2698261592E+00 1.2597062549E+01 1.2524016217E+01 + 1.2629167877E+01 3.0192746991E-02 5.6430070580E-02 + 1.2535361046E+01 1.8886400625E+01 6.2656789628E+00 +:V: + -1.7816416508E-05 6.9287104298E-04 4.4173494708E-04 + 2.8659649260E-05 -1.5963276425E-04 5.1833834230E-04 + 6.8946493586E-04 -4.5652114727E-04 -3.1086883124E-04 + -2.8344968811E-04 -1.3863204333E-04 -4.4980186930E-04 + 3.3322687246E-04 4.0616089168E-04 -3.2892051261E-05 + -1.2094037004E-04 3.7383414316E-04 -5.9381614982E-05 + -7.4908507765E-04 -5.9626464550E-04 2.6646647722E-04 + 9.1563077462E-05 1.3256104629E-04 3.9304164662E-04 + 5.0600650802E-04 -4.7568591273E-04 1.4606832386E-04 + -4.4072697731E-04 -2.4603295313E-05 -6.2083611561E-04 + 3.4872756271E-05 1.6978933170E-05 -3.1009798701E-04 + 5.3358931363E-05 -4.7874250403E-04 4.3904195404E-04 + 5.0375232743E-04 -4.6003630377E-05 3.8311210258E-04 + 7.4000448705E-04 3.4739392968E-04 -5.1420731417E-05 + -7.4849387533E-04 5.7514211624E-04 -3.0139105003E-04 + 1.5152386031E-05 -8.4119028851E-04 -5.7866086842E-05 + -3.6982104702E-04 6.0001800472E-04 -2.7471565042E-05 + -1.9342607956E-04 9.4238856026E-06 -4.3188989852E-04 + 2.0844174077E-04 1.8205013255E-04 3.8996068744E-04 + -3.7086202055E-04 -4.0768862482E-05 -2.4144202619E-04 +:F: + -3.4120759486E-03 3.0659813445E-03 1.0248758834E-03 + -1.9962306801E-03 -1.3725704792E-03 9.2913778678E-04 + 1.1735152934E-02 -1.4024561697E-03 -1.7347367968E-03 + 1.1577395076E-02 -1.1062652563E-03 -5.2958014695E-04 + 1.2077109948E-02 7.9775718595E-04 7.6926411626E-04 + 1.4128261336E-02 2.4605241711E-03 3.0005356309E-04 + 1.1283419963E-02 -2.1431174534E-03 1.3968636685E-04 + 1.3341830970E-02 6.2420224730E-04 3.9976233963E-05 + 1.3877568072E-02 -8.1851831869E-04 -4.6541726896E-04 + 1.6010944488E-04 1.5554954371E-03 -1.8579533744E-03 + 4.9711782045E-03 -1.3780404591E-03 -9.0051046395E-04 + -1.1683852234E-02 -2.0899997598E-03 2.4486133815E-03 + -1.1644665125E-02 7.7745309228E-04 1.3614673062E-03 + -1.1855423380E-02 -7.2380146623E-04 -1.0178771322E-04 + -1.4113643544E-02 2.3031500349E-03 -1.7176591835E-03 + -1.1600542789E-02 -2.0979052865E-03 7.0874194099E-04 + -1.3244813447E-02 1.7008883854E-03 5.0207094171E-04 + -1.4023461587E-02 -1.9956950897E-04 -1.0351399369E-03 + 2.5503648027E-03 -2.2091317341E-04 1.3385406756E-02 + -2.1276820176E-03 2.6770543275E-04 -1.3266509392E-02 +:ANGLES: + 90.000 89.999 90.000 +:VOLUME: 6.7440691052E+03 +:LATVEC_SCALE: + 1.8893732489E+01 1.8893268735E+01 1.8892835703E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -6.6433146881E-06 9.9999999998E-01 0.0000000000E+00 + 1.1837517311E-05 -2.5536145011E-06 9.9999999993E-01 +:STRIO: + 7.1299761139E-01 -8.7479687769E-02 1.4210588018E-01 + -8.7479687769E-02 7.3042029814E-01 -2.7706672877E-02 + 1.4210588018E-01 -2.7706672877E-02 4.7485428953E-01 +:STRESS: + 4.9131670277E+00 -6.8678901521E-03 2.9615024805E-03 + -6.8678901521E-03 5.5265212815E+00 5.2250432413E-03 + 2.9615024805E-03 5.2250432413E-03 5.8127932710E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2001694163E+00 -8.0611797617E-02 1.3914437770E-01 + -8.0611797617E-02 -4.7961009834E+00 -3.2931716118E-02 + 1.3914437770E-01 -3.2931716118E-02 -5.3379389815E+00 +:PRESIO: 6.3942406635E-01 +:PRES: -5.4174938601E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7780697937E+00 +:PRESIG: 6.7307796458E-01 +:MIND: +Al - Al: 6.1242614409E+00 +C - C: 6.2101162765E+00 +Al - C: 6.2328793438E+00 + + +:MDSTEP: 6 +:MDTM: 157.23 +:TWIST: 0 +:TEL: 2400 +:TIO: 2454.94324451122 +:TEN: -2.6049341613E+00 +:KEN: 1.1078438282E-02 +:KENIG: 1.1661513982E-02 +:FEN: -2.6160125996E+00 +:UEN: -2.6088694156E+00 +:TSEN: -7.1431839567E-03 +:NPH_HAMIL: 6.6123522828E-05 +:NPH_ENTHALPY: -5.2074687712E+01 +:R: + 1.8889158140E+01 1.4263721729E-01 9.1067184872E-02 + 6.4691293524E-03 1.8858503610E+01 6.4038355284E+00 + 1.3944703490E-01 1.8797132901E+01 1.2529807012E+01 + 1.8830570291E+01 6.2685825798E+00 1.8797764754E+01 + 6.5723679939E-02 6.3808669087E+00 6.2899485350E+00 + 1.8863533822E+01 6.3738582315E+00 1.2581414754E+01 + 1.8734009295E+01 1.2471309013E+01 5.5022282027E-02 + 1.5503667808E-02 1.2621406491E+01 6.3780837261E+00 + 1.0109461872E-01 1.2495967713E+01 1.2623997455E+01 + 6.2060908208E+00 1.8885848156E+01 1.8762637814E+01 + 6.3034970167E+00 3.7254795774E-03 6.2329789744E+00 + 6.3114296256E+00 1.8792663674E+01 1.2684023801E+01 + 6.4044638524E+00 6.2874639312E+00 7.8914033598E-02 + 6.4534278916E+00 6.3689888141E+00 6.2862702627E+00 + 6.1464127344E+00 6.4154848741E+00 1.2531759643E+01 + 6.3037606461E+00 1.2420621727E+01 1.8878532795E+01 + 6.2242718589E+00 1.2717810025E+01 6.2911132245E+00 + 6.2610345427E+00 1.2596101802E+01 1.2504678474E+01 + 1.2636707940E+01 3.7706248400E-02 7.3065456648E-02 + 1.2518753413E+01 1.8882722999E+01 6.2544469587E+00 +:V: + -2.0718342512E-05 6.9583906705E-04 4.4272323497E-04 + 2.7107487235E-05 -1.6094125068E-04 5.1930607391E-04 + 6.9938544696E-04 -4.5790054182E-04 -3.1254265526E-04 + -2.7385535383E-04 -1.3965778753E-04 -4.5036252533E-04 + 3.4336827275E-04 4.0697801544E-04 -3.2159338287E-05 + -1.0898934412E-04 3.7619801974E-04 -5.9101056950E-05 + -7.3979904570E-04 -5.9839268698E-04 2.6661914169E-04 + 1.0287394392E-04 1.3313874091E-04 3.9313789847E-04 + 5.1777189669E-04 -4.7650703429E-04 1.4563712055E-04 + -4.4093550173E-04 -2.3133703545E-05 -6.2268807248E-04 + 3.9248708476E-05 1.5684640288E-05 -3.1095086374E-04 + 4.3550290837E-05 -4.8076723515E-04 4.4139099834E-04 + 4.9410913952E-04 -4.5249584080E-05 3.8442748384E-04 + 7.3017696202E-04 3.4677190765E-04 -5.1520959195E-05 + -7.6050938839E-04 5.7738194329E-04 -3.0303941314E-04 + 5.4955959227E-06 -8.4328754596E-04 -5.7216235848E-05 + -3.8105802729E-04 6.0165469563E-04 -2.6988339432E-05 + -2.0530503901E-04 9.2403629038E-06 -4.3291137527E-04 + 2.1385889087E-04 1.8161005725E-04 4.1572980255E-04 + -3.7541498432E-04 -4.0199081350E-05 -2.6693062047E-04 +:F: + -3.4885710199E-03 3.8219094569E-03 1.2009860889E-03 + -1.7031874608E-03 -1.7008342823E-03 1.2298146812E-03 + 1.1716052018E-02 -1.7704037188E-03 -2.1499094895E-03 + 1.1313341168E-02 -1.2972223776E-03 -6.8251961601E-04 + 1.1978606284E-02 1.0416531824E-03 9.8675174540E-04 + 1.4333789487E-02 3.0708545474E-03 3.8123027813E-04 + 1.0976961609E-02 -2.7643455177E-03 1.4063912204E-04 + 1.3549984359E-02 7.1621801732E-04 8.0445116694E-05 + 1.4003844386E-02 -1.0197532092E-03 -5.9253777538E-04 + -5.5861295972E-04 1.9508428198E-03 -2.3815203052E-03 + 5.4328771813E-03 -1.7060497610E-03 -1.0418346510E-03 + -1.1665803973E-02 -2.6075479084E-03 3.0202854122E-03 + -1.1411134642E-02 1.0242183121E-03 1.6686250855E-03 + -1.1691334210E-02 -8.4938123848E-04 -1.1306100072E-04 + -1.4309155860E-02 2.8876193863E-03 -2.1327468502E-03 + -1.1379336772E-02 -2.6808176085E-03 8.5636070363E-04 + -1.3409533255E-02 2.0455338590E-03 6.4814197907E-04 + -1.4197448392E-02 -2.3785634686E-04 -1.2777273930E-03 + 3.1667623798E-03 -2.6631821268E-04 1.3860759146E-02 + -2.6581003281E-03 3.4168060024E-04 -1.3702182277E-02 +:ANGLES: + 90.001 89.999 90.000 +:VOLUME: 6.7419390459E+03 +:LATVEC_SCALE: + 1.8891972787E+01 1.8891273440E+01 1.8890622799E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.0016318144E-05 9.9999999995E-01 0.0000000000E+00 + 1.7771931797E-05 -3.8711310191E-06 9.9999999983E-01 +:STRIO: + 7.1796901210E-01 -9.0692608018E-02 1.4403452499E-01 + -9.0692608018E-02 7.3522677177E-01 -2.7459175153E-02 + 1.4403452499E-01 -2.7459175153E-02 4.8060340585E-01 +:STRESS: + 4.9006600368E+00 -8.7352486926E-03 2.2089744325E-03 + -8.7352486926E-03 5.5213644603E+00 7.6331627380E-03 + 2.2089744325E-03 7.6331627380E-03 5.8165587944E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1826910247E+00 -8.1957359325E-02 1.4182555056E-01 + -8.1957359325E-02 -4.7861376885E+00 -3.5092337891E-02 + 1.4182555056E-01 -3.5092337891E-02 -5.3359553886E+00 +:PRESIO: 6.4459972990E-01 +:PRES: -5.4128610972E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7682613673E+00 +:PRESIG: 6.7852603148E-01 +:MIND: +Al - Al: 6.0802407795E+00 +C - C: 6.1827529706E+00 +Al - C: 6.2153058488E+00 + + +:MDSTEP: 7 +:MDTM: 156.97 +:TWIST: 0 +:TEL: 2400 +:TIO: 2477.96623464723 +:TEN: -2.6049540766E+00 +:KEN: 1.1182334279E-02 +:KENIG: 1.1770878189E-02 +:FEN: -2.6161364109E+00 +:UEN: -2.6090163892E+00 +:TSEN: -7.1200217029E-03 +:NPH_HAMIL: 8.5470314126E-05 +:NPH_ENTHALPY: -5.2074668366E+01 +:R: + 1.8886132845E+01 1.7144866156E-01 1.0937545815E-01 + 7.5284205142E-03 1.8849421626E+01 6.4244223519E+00 + 1.6855831465E-01 1.8775772463E+01 1.2515088906E+01 + 1.8817453625E+01 6.2619624808E+00 1.8776494034E+01 + 8.0137088527E-02 6.3968892687E+00 6.2877520158E+00 + 1.8857236069E+01 6.3886342114E+00 1.2577209515E+01 + 1.8701477750E+01 1.2444945552E+01 6.6037841129E-02 + 1.9984059636E-02 1.2625312905E+01 6.3934389709E+00 + 1.2276913715E-01 1.2474649356E+01 1.2628232280E+01 + 6.1872186432E+00 1.8882502625E+01 1.8734219344E+01 + 6.3045547537E+00 4.3336317093E-03 6.2192312199E+00 + 6.3123370565E+00 1.8770343737E+01 1.2700538100E+01 + 6.4239506644E+00 6.2848145186E+00 9.4822451839E-02 + 6.4827065622E+00 6.3824911470E+00 6.2832548311E+00 + 6.1141044628E+00 6.4385686596E+00 1.2517434383E+01 + 6.3031711188E+00 1.2384112649E+01 1.8873528374E+01 + 6.2075854937E+00 1.2741094127E+01 6.2891244053E+00 + 6.2516404068E+00 1.2594863494E+01 1.2485003545E+01 + 1.2644261758E+01 4.5197988755E-02 9.0780520418E-02 + 1.2501701580E+01 1.8878672139E+01 6.2419991628E+00 +:V: + -2.3688819993E-05 6.9945142691E-04 4.4386970651E-04 + 2.5802085480E-05 -1.6252616560E-04 5.2053415547E-04 + 7.0930011571E-04 -4.5960065506E-04 -3.1456867596E-04 + -2.6449175727E-04 -1.4084212691E-04 -4.5106010579E-04 + 3.5343626329E-04 4.0800571486E-04 -3.1246151031E-05 + -9.6867430913E-05 3.7907789127E-04 -5.8752550463E-05 + -7.3078135489E-04 -6.0105728123E-04 2.6677864270E-04 + 1.1436256338E-04 1.3379632216E-04 3.9327753703E-04 + 5.2964895692E-04 -4.7750321940E-04 1.4509996369E-04 + -4.4174939920E-04 -2.1331649020E-05 -6.2498624575E-04 + 4.4016842562E-05 1.4118243799E-05 -3.1192917094E-04 + 3.3756702613E-05 -4.8323503681E-04 4.4422022823E-04 + 4.8467212210E-04 -4.4292445833E-05 3.8600787762E-04 + 7.2049843692E-04 3.4605167354E-04 -5.1634993583E-05 + -7.7270094945E-04 5.8012195115E-04 -3.0503908029E-04 + -3.9780273728E-06 -8.4588931301E-04 -5.6443356149E-05 + -3.9243806520E-04 6.0358933927E-04 -2.6384148030E-05 + -2.1733208392E-04 9.0293968175E-06 -4.3414368698E-04 + 2.2043453064E-04 1.8109171335E-04 4.4245194367E-04 + -3.8097637123E-04 -3.9487645798E-05 -2.9329070766E-04 +:F: + -3.5735630376E-03 4.5633588886E-03 1.3755916601E-03 + -1.4099272775E-03 -2.0218669103E-03 1.5194619511E-03 + 1.1688078872E-02 -2.1434437312E-03 -2.5522097222E-03 + 1.1038105413E-02 -1.4759377892E-03 -8.3058538878E-04 + 1.1884875659E-02 1.2774574147E-03 1.2010946648E-03 + 1.4536735270E-02 3.6687668091E-03 4.6452465491E-04 + 1.0675226619E-02 -3.3879447053E-03 1.3944081505E-04 + 1.3757479680E-02 8.0715939351E-04 1.2160107154E-04 + 1.4117632151E-02 -1.2118809856E-03 -7.2346823868E-04 + -1.2608139751E-03 2.3480224406E-03 -2.8855648784E-03 + 5.9015058863E-03 -2.0259884702E-03 -1.1811380954E-03 + -1.1647563910E-02 -3.1194900535E-03 3.5660637778E-03 + -1.1173502670E-02 1.2619803976E-03 1.9714554903E-03 + -1.1530623754E-02 -9.7585207933E-04 -1.2999927581E-04 + -1.4496143323E-02 3.4650169727E-03 -2.5389111657E-03 + -1.1162622918E-02 -3.2553009352E-03 1.0049403869E-03 + -1.3565695585E-02 2.3798983055E-03 7.8951143207E-04 + -1.4363878986E-02 -2.6482533901E-04 -1.5130760197E-03 + 3.7726177649E-03 -3.0799882277E-04 1.4381214312E-02 + -3.1879218803E-03 4.1886919942E-04 -1.4179947432E-02 +:ANGLES: + 90.001 89.999 90.000 +:VOLUME: 6.7393847800E+03 +:LATVEC_SCALE: + 1.8889864129E+01 1.8888879955E+01 1.8887966870E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.4098033710E-05 9.9999999990E-01 0.0000000000E+00 + 2.4932873694E-05 -5.4919994383E-06 9.9999999967E-01 +:STRIO: + 7.2424711610E-01 -9.4057702166E-02 1.4635968001E-01 + -9.4057702166E-02 7.4113794768E-01 -2.7269851297E-02 + 1.4635968001E-01 -2.7269851297E-02 4.8728950869E-01 +:STRESS: + 4.8870229803E+00 -1.0652880894E-02 7.7180651708E-04 + -1.0652880894E-02 5.5142536669E+00 1.0425875857E-02 + 7.7180651708E-04 1.0425875857E-02 5.8204135410E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1627758642E+00 -8.3404821271E-02 1.4558787350E-01 + -8.3404821271E-02 -4.7731157192E+00 -3.7695727154E-02 + 1.4558787350E-01 -3.7695727154E-02 -5.3331240323E+00 +:PRESIO: 6.5089152416E-01 +:PRES: -5.4072300627E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7563385386E+00 +:PRESIG: 6.8514897280E-01 +:MIND: +Al - Al: 6.0360205086E+00 +C - C: 6.1532235592E+00 +Al - C: 6.1972060925E+00 + + +:MDSTEP: 8 +:MDTM: 157.57 +:TWIST: 0 +:TEL: 2400 +:TIO: 2505.10463871269 +:TEN: -2.6049784669E+00 +:KEN: 1.1304801931E-02 +:KENIG: 1.1899791506E-02 +:FEN: -2.6162832688E+00 +:UEN: -2.6091902655E+00 +:TSEN: -7.0930033260E-03 +:NPH_HAMIL: 8.3314619680E-05 +:NPH_ENTHALPY: -5.2074670521E+01 +:R: + 1.8882635925E+01 2.0041436509E-01 1.2772858091E-01 + 8.5332715070E-03 1.8839870803E+01 6.4449107147E+00 + 1.9807424676E-01 1.8753938967E+01 1.2499988567E+01 + 1.8804393421E+01 6.2551533431E+00 1.8754754433E+01 + 9.4964901049E-02 6.4128190770E+00 6.2854496597E+00 + 1.8851107617E+01 6.4033987998E+00 1.2572725443E+01 + 1.8668964878E+01 1.2418202888E+01 7.7056614034E-02 + 2.4941050538E-02 1.2628979508E+01 6.4086480340E+00 + 1.4493855248E-01 1.2453022799E+01 1.2632145359E+01 + 6.1681988980E+00 1.8878835268E+01 1.8705261815E+01 + 6.3057092130E+00 4.8692949032E-03 6.2052968055E+00 + 6.3127263206E+00 1.8747516733E+01 1.2716877846E+01 + 6.4429264134E+00 6.2820767761E+00 1.1079661859E-01 + 6.5114679905E+00 6.3958230619E+00 6.2800873251E+00 + 6.0811915026E+00 6.4616326762E+00 1.2502727792E+01 + 6.3020927450E+00 1.2347224492E+01 1.8868116060E+01 + 6.1903124661E+00 1.2764190199E+01 6.2870156430E+00 + 6.2416388124E+00 1.2593346907E+01 1.2464983609E+01 + 1.2651877412E+01 5.2664551593E-02 1.0961540446E-01 + 1.2484165324E+01 1.8874254716E+01 6.2282985892E+00 +:V: + -2.6735475347E-05 7.0369363585E-04 4.4517287173E-04 + 2.4743876821E-05 -1.6438109177E-04 5.2201272748E-04 + 7.1920163124E-04 -4.6162551619E-04 -3.1693558575E-04 + -2.5536746345E-04 -1.4217351987E-04 -4.5189065892E-04 + 3.6343480416E-04 4.0923696938E-04 -3.0155328952E-05 + -8.4576981037E-05 3.8246223004E-04 -5.8334195113E-05 + -7.2202724489E-04 -6.0425936704E-04 2.6694296660E-04 + 1.2602857501E-04 1.3453286226E-04 3.9346125218E-04 + 5.4162711776E-04 -4.7866626915E-04 1.4445377843E-04 + -4.4315426221E-04 -1.9195552356E-05 -6.2771218992E-04 + 4.9183309690E-05 1.2286337950E-05 -3.1303101900E-04 + 2.3977589589E-05 -4.8614043566E-04 4.4750590343E-04 + 4.7544361953E-04 -4.3141030817E-05 3.8784911328E-04 + 7.1096552768E-04 3.4523272958E-04 -5.1767480463E-05 + -7.8506055412E-04 5.8335517644E-04 -3.0738191733E-04 + -1.3272572821E-05 -8.4898709372E-04 -5.5546512947E-05 + -4.0395412549E-04 6.0581317754E-04 -2.5663084339E-05 + -2.2950089871E-04 8.8006491564E-06 -4.3558058021E-04 + 2.2814783119E-04 1.8050214147E-04 4.7021651121E-04 + -3.8754461905E-04 -3.8628111877E-05 -3.2060625060E-04 +:F: + -3.6679281134E-03 5.2843271006E-03 1.5478920309E-03 + -1.1158009241E-03 -2.3346311635E-03 1.7964469765E-03 + 1.1650826239E-02 -2.5208024057E-03 -2.9399768985E-03 + 1.0752869330E-02 -1.6392990022E-03 -9.7394222208E-04 + 1.1794985092E-02 1.5044690883E-03 1.4117277224E-03 + 1.4735544567E-02 4.2512143678E-03 5.5020276657E-04 + 1.0379257298E-02 -4.0110271731E-03 1.3559929613E-04 + 1.3963735931E-02 8.9684345622E-04 1.6373743950E-04 + 1.4217767858E-02 -1.3935507203E-03 -8.5767122241E-04 + -1.9450945971E-03 2.7468679626E-03 -3.3648689426E-03 + 6.3773241418E-03 -2.3380894366E-03 -1.3177621067E-03 + -1.1630026840E-02 -3.6236393550E-03 4.0807345813E-03 + -1.0933542856E-02 1.4876251376E-03 2.2683983172E-03 + -1.1373660916E-02 -1.1024800244E-03 -1.5231941485E-04 + -1.4671615378E-02 4.0326052954E-03 -2.9344686810E-03 + -1.0950362542E-02 -3.8176199426E-03 1.1546570594E-03 + -1.3712700759E-02 2.7035208769E-03 9.2559740565E-04 + -1.4521777469E-02 -2.8004464120E-04 -1.7406510624E-03 + 4.3665756393E-03 -3.4592507958E-04 1.4949806315E-02 + -3.7163757027E-03 4.9963565871E-04 -1.4703139360E-02 +:ANGLES: + 90.001 89.998 90.000 +:VOLUME: 6.7364073476E+03 +:LATVEC_SCALE: + 1.8887407893E+01 1.8886089038E+01 1.8884867798E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.8902250441E-05 9.9999999982E-01 0.0000000000E+00 + 3.3355086773E-05 -7.4392078919E-06 9.9999999942E-01 +:STRIO: + 7.3183221361E-01 -9.7579583504E-02 1.4909730383E-01 + -9.7579583504E-02 7.4815499789E-01 -2.7140879478E-02 + 1.4909730383E-01 -2.7140879478E-02 4.9494534762E-01 +:STRESS: + 4.8722077830E+00 -1.2614329954E-02 -1.3916790973E-03 + -1.2614329954E-02 5.5051377691E+00 1.3572098663E-02 + -1.3916790973E-03 1.3572098663E-02 5.8243803142E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1403755694E+00 -8.4965253549E-02 1.5048898293E-01 + -8.4965253549E-02 -4.7569827712E+00 -4.0712978140E-02 + 1.5048898293E-01 -4.0712978140E-02 -5.3294349666E+00 +:PRESIO: 6.5831085304E-01 +:PRES: -5.4005752888E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7422644357E+00 +:PRESIG: 6.9295879267E-01 +:MIND: +Al - Al: 5.9915670151E+00 +C - C: 6.1214614752E+00 +Al - C: 6.1785220316E+00 + + +:MDSTEP: 9 +:MDTM: 157.66 +:TWIST: 0 +:TEL: 2400 +:TIO: 2536.39188850204 +:TEN: -2.6050066748E+00 +:KEN: 1.1445992106E-02 +:KENIG: 1.2048412743E-02 +:FEN: -2.6164526669E+00 +:UEN: -2.6093905641E+00 +:TSEN: -7.0621028023E-03 +:NPH_HAMIL: 7.2029148818E-05 +:NPH_ENTHALPY: -5.2074681807E+01 +:R: + 1.8878665675E+01 2.2955875397E-01 1.4613211681E-01 + 9.4939622751E-03 1.8829841197E+01 6.4653096918E+00 + 2.2799326853E-01 1.8731620366E+01 1.2484492715E+01 + 1.8791382180E+01 6.2481494465E+00 1.8732541314E+01 + 1.1020387069E-01 6.4286640384E+00 6.2830487607E+00 + 1.8845157392E+01 6.4181718927E+00 1.2567965508E+01 + 1.8636462349E+01 1.2391060504E+01 8.8078234470E-02 + 3.0381832632E-02 1.2632409767E+01 6.4237119532E+00 + 1.6760635014E-01 1.2431082462E+01 1.2635731782E+01 + 6.1490091318E+00 1.8874860431E+01 1.8675749106E+01 + 6.3069776362E+00 5.3214647819E-03 6.1911712506E+00 + 6.3125989018E+00 1.8724166176E+01 1.2733060403E+01 + 6.4613995720E+00 6.2792588985E+00 1.2684644823E-01 + 6.5397177909E+00 6.4089800427E+00 6.2767669540E+00 + 6.0476692478E+00 6.4846961169E+00 1.2487626410E+01 + 6.3005341300E+00 1.2309938591E+01 1.8862300992E+01 + 6.1724485454E+00 1.2787109431E+01 6.2847916863E+00 + 6.2310252884E+00 1.2591551821E+01 1.2444611130E+01 + 1.2659602165E+01 6.0102813114E-02 1.2961397750E-01 + 1.2466104681E+01 1.8869477864E+01 6.2133047407E+00 +:V: + -2.9866174506E-05 7.0854647246E-04 4.4663087515E-04 + 2.3934132576E-05 -1.6649883139E-04 5.2372981134E-04 + 7.2908178435E-04 -4.6397847151E-04 -3.1963042317E-04 + -2.4649030550E-04 -1.4363815536E-04 -4.5285030094E-04 + 3.7336729188E-04 4.1066427533E-04 -2.8890178872E-05 + -7.2121645181E-05 3.8633697414E-04 -5.7843846332E-05 + -7.1353114995E-04 -6.0799744804E-04 2.6710964620E-04 + 1.3787087391E-04 1.3534716070E-04 3.9369028215E-04 + 5.5369483687E-04 -4.7998685497E-04 1.4369562775E-04 + -4.4513475107E-04 -1.6724067270E-05 -6.3084251208E-04 + 5.4754247022E-05 1.0196046325E-05 -3.1425383706E-04 + 1.4212279675E-05 -4.8947668894E-04 4.5121940557E-04 + 4.6642476997E-04 -4.1806549188E-05 3.8994574350E-04 + 7.0157432471E-04 3.4431475516E-04 -5.1922752877E-05 + -7.9757769858E-04 5.8707276104E-04 -3.1005853887E-04 + -2.2391966272E-05 -8.5256920733E-04 -5.4524934614E-05 + -4.1559845272E-04 6.0831683432E-04 -2.4829349935E-05 + -2.4180440423E-04 8.5642743294E-06 -4.3721538795E-04 + 2.3697442923E-04 1.7984816357E-04 4.9911851788E-04 + -3.9511664531E-04 -3.7613335216E-05 -3.4896747811E-04 +:F: + -3.7713497331E-03 5.9794794696E-03 1.7177806960E-03 + -8.1949529077E-04 -2.6382740082E-03 2.0573255264E-03 + 1.1602585786E-02 -2.9015924978E-03 -3.3108575399E-03 + 1.0458226508E-02 -1.7850030059E-03 -1.1125694452E-03 + 1.1708546245E-02 1.7222192267E-03 1.6180819798E-03 + 1.4928661169E-02 4.8151498430E-03 6.3856470373E-04 + 1.0089951984E-02 -4.6306176307E-03 1.2851626544E-04 + 1.4167548462E-02 9.8479347462E-04 2.0786325139E-04 + 1.4303109313E-02 -1.5634175594E-03 -9.9531539199E-04 + -2.6105709729E-03 3.1469446930E-03 -3.8128296637E-03 + 6.8599879644E-03 -2.6408253847E-03 -1.4507166569E-03 + -1.1612529922E-02 -4.1191092823E-03 4.5578400647E-03 + -1.0692375288E-02 1.6985399213E-03 2.5579437683E-03 + -1.1221336982E-02 -1.2295567458E-03 -1.7954185882E-04 + -1.4832616415E-02 4.5885602151E-03 -3.3181008440E-03 + -1.0742233374E-02 -4.3638805013E-03 1.3049331583E-03 + -1.3849432095E-02 3.0153684541E-03 1.0566863553E-03 + -1.4670296299E-02 -2.8277186539E-04 -1.9599800816E-03 + 4.9461872729E-03 -3.8035613336E-04 1.5569358169E-02 + -4.2425683314E-03 5.8434931735E-04 -1.5274982456E-02 +:ANGLES: + 90.001 89.998 90.001 +:VOLUME: 6.7330079767E+03 +:LATVEC_SCALE: + 1.8884605622E+01 1.8882901654E+01 1.8881325475E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -2.4443981515E-05 9.9999999970E-01 0.0000000000E+00 + 4.3083598873E-05 -9.7394543792E-06 9.9999999902E-01 +:STRIO: + 7.4072396492E-01 -1.0126342699E-01 1.5226497221E-01 + -1.0126342699E-01 7.5627679471E-01 -2.7074614612E-02 + 1.5226497221E-01 -2.7074614612E-02 5.0360707908E-01 +:STRESS: + 4.8561362375E+00 -1.4622040964E-02 -4.3327286785E-03 + -1.4622040964E-02 5.4939127553E+00 1.7028690779E-02 + -4.3327286785E-03 1.7028690779E-02 5.8284027112E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1154122726E+00 -8.6641386024E-02 1.5659770089E-01 + -8.6641386024E-02 -4.7376359605E+00 -4.4103305392E-02 + 1.5659770089E-01 -4.4103305392E-02 -5.3247956321E+00 +:PRESIO: 6.6686927957E-01 +:PRES: -5.3928172346E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7259479551E+00 +:PRESIG: 7.0196766271E-01 +:MIND: +Al - Al: 5.9468495354E+00 +C - C: 6.0873950323E+00 +Al - C: 6.1591960026E+00 + + +:MDSTEP: 10 +:MDTM: 138.14 +:TWIST: 0 +:TEL: 2400 +:TIO: 2571.85978710411 +:TEN: -2.6050379998E+00 +:KEN: 1.1606048322E-02 +:KENIG: 1.2216892970E-02 +:FEN: -2.6166440482E+00 +:UEN: -2.6096166978E+00 +:TSEN: -7.0273503541E-03 +:NPH_HAMIL: 6.4716791520E-05 +:NPH_ENTHALPY: -5.2074689119E+01 +:R: + 1.8874220250E+01 2.5890535537E-01 1.6459154513E-01 + 1.0420900348E-02 1.8819323371E+01 6.4856278024E+00 + 2.5831354600E-01 1.8708804664E+01 1.2468588672E+01 + 1.8778412431E+01 6.2409456960E+00 1.8709850223E+01 + 1.2585092582E-01 6.4444315891E+00 6.2805564681E+00 + 1.8839394409E+01 6.4329727722E+00 1.2562932782E+01 + 1.8603962211E+01 1.2363498146E+01 9.9102223021E-02 + 3.6313561320E-02 1.2635607210E+01 6.4386318401E+00 + 1.9077562034E-01 1.2408823275E+01 1.2638986529E+01 + 6.1296277736E+00 1.8870592652E+01 1.8645666209E+01 + 6.3083776201E+00 5.6794458834E-03 6.1768502096E+00 + 6.3119564666E+00 1.8700276055E+01 1.2749101839E+01 + 6.4793787198E+00 6.2763686365E+00 1.4298159541E-01 + 6.5674615471E+00 6.4219576117E+00 6.2732927640E+00 + 6.0135337767E+00 6.5077778008E+00 1.2472117211E+01 + 6.2985039891E+00 1.2272236916E+01 1.8856088346E+01 + 6.1539899712E+00 1.2809862722E+01 6.2824571187E+00 + 6.2197958698E+00 1.2589478554E+01 1.2423878874E+01 + 1.2667482277E+01 6.7509921885E-02 1.5082405305E-01 + 1.2447480015E+01 1.8864349217E+01 6.1969733616E+00 +:V: + -3.3088450349E-05 7.1398655347E-04 4.4824128518E-04 + 2.3375379913E-05 -1.6887171180E-04 5.2567047787E-04 + 7.3893148706E-04 -4.6666226753E-04 -3.2263785765E-04 + -2.3786758806E-04 -1.4522122210E-04 -4.5393533235E-04 + 3.8323688656E-04 4.1227988176E-04 -2.7454380867E-05 + -5.9506224688E-05 3.9068552168E-04 -5.7279088950E-05 + -7.0528649067E-04 -6.1226689728E-04 2.6727582329E-04 + 1.4988752872E-04 1.3623772540E-04 3.9396652409E-04 + 5.6583927860E-04 -4.8145448611E-04 1.4282264295E-04 + -4.4767495752E-04 -1.3916186450E-05 -6.3434840130E-04 + 6.0735435672E-05 7.8559152645E-06 -3.1559440236E-04 + 4.4602635471E-06 -4.9323650490E-04 4.5532706136E-04 + 4.5761583198E-04 -4.0302258754E-05 3.9229094539E-04 + 6.9232005994E-04 3.4329735503E-04 -5.2104798101E-05 + -8.1023975161E-04 5.9126403666E-04 -3.1305829777E-04 + -3.1340145234E-05 -8.5662086601E-04 -5.3378172092E-05 + -4.2736262619E-04 6.1108974474E-04 -2.3886707034E-05 + -2.5423434352E-04 8.3315292566E-06 -4.3904135002E-04 + 2.4688519180E-04 1.7913612881E-04 5.2925848075E-04 + -4.0368761124E-04 -3.6435357354E-05 -3.7847090640E-04 +:F: + -3.8833406237E-03 6.6441834904E-03 1.8839565240E-03 + -5.1936846975E-04 -2.9324878559E-03 2.2984906840E-03 + 1.1543000099E-02 -3.2852384801E-03 -3.6614911795E-03 + 1.0154875719E-02 -1.9129611289E-03 -1.2469095638E-03 + 1.1625405141E-02 1.9305701281E-03 1.8198188189E-03 + 1.5114888529E-02 5.3575175028E-03 7.2993998127E-04 + 9.8088468566E-03 -5.2421761915E-03 1.1784898948E-04 + 1.4368141923E-02 1.0707821437E-03 2.5453601034E-04 + 1.4371730807E-02 -1.7200561625E-03 -1.1360261718E-03 + -3.2567135381E-03 3.5478346756E-03 -4.2231182461E-03 + 7.3489431847E-03 -2.9323057228E-03 -1.5794129369E-03 + -1.1595355404E-02 -4.6054298254E-03 4.9917531687E-03 + -1.0450996422E-02 1.8924401625E-03 2.8382981583E-03 + -1.1074811997E-02 -1.3569469488E-03 -2.1130387466E-04 + -1.4977045365E-02 5.1303492018E-03 -3.6881039157E-03 + -1.0538612529E-02 -4.8905373047E-03 1.4555640841E-03 + -1.3975423533E-02 3.3136257072E-03 1.1834983256E-03 + -1.4807476634E-02 -2.7112605947E-04 -2.1712941051E-03 + 5.5087924006E-03 -4.1153176461E-04 1.6242779954E-02 + -4.7654801425E-03 6.7349443270E-04 -1.5898824705E-02 +:ANGLES: + 90.002 89.997 90.001 +:VOLUME: 6.7291880912E+03 +:LATVEC_SCALE: + 1.8881459029E+01 1.8879318981E+01 1.8877339816E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -3.0739497887E-05 9.9999999953E-01 0.0000000000E+00 + 5.4174362639E-05 -1.2422817341E-05 9.9999999846E-01 +:STRIO: + 7.5092106909E-01 -1.0511489927E-01 1.5588220216E-01 + -1.0511489927E-01 7.6549971021E-01 -2.7073475846E-02 + 1.5588220216E-01 -2.7073475846E-02 5.1331431036E-01 +:STRESS: + 4.8387802198E+00 -1.6683499800E-02 -8.0978217749E-03 + -1.6683499800E-02 5.4804962665E+00 2.0743609098E-02 + -8.0978217749E-03 2.0743609098E-02 5.8324867002E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.0878591507E+00 -8.8431399474E-02 1.6398002393E-01 + -8.8431399474E-02 -4.7149965563E+00 -4.7817084944E-02 + 1.6398002393E-01 -4.7817084944E-02 -5.3191723899E+00 +:PRESIO: 6.7657836322E-01 +:PRES: -5.3839210622E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7073426990E+00 +:PRESIG: 7.1218775076E-01 +:MIND: +Al - Al: 5.9018406329E+00 +C - C: 6.0509471301E+00 +Al - C: 6.1391708757E+00 diff --git a/tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.refout b/tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.refout new file mode 100644 index 00000000..ac451c6b --- /dev/null +++ b/tests/Al18C2_NPH_full_flex/high_accuracy/Al18C2_NPH_full_flex.refout @@ -0,0 +1,653 @@ +*************************************************************************** +* SPARC (version December 03, 2025) * +* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * +* Distributed under GNU General Public License 3 (GPL) * +* Start time: Sun Apr 5 14:09:52 2026 * +*************************************************************************** + Input parameters +*************************************************************************** +LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 +LATVEC: +1.000000000000000 0.000000000000000 0.000000000000000 +0.000000000000000 1.000000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 +WARNING: This system is cuboidal. To get the best performance, please align the lattice vectors onto standard cartesian coordinate. +FD_GRID: 126 126 126 +FD_ORDER: 12 +BC: P P P +KPOINT_GRID: 1 1 1 +KPOINT_SHIFT: 0 0 0 +SPIN_TYP: 0 +ELEC_TEMP_TYPE: Fermi-Dirac +ELEC_TEMP: 2400 +EXCHANGE_CORRELATION: GGA_PBE +HUBBARD_FLAG: 0 +NSTATES: 80 +CHEB_DEGREE: 42 +CHEFSI_BOUND_FLAG: 0 +CALC_STRESS: 1 +TWTIME: 1E+09 +MD_FLAG: 1 +MD_METHOD: NPH +MD_TIMESTEP: 1 +MD_NSTEP: 10 +ION_VEL_DSTR: 2 +ION_VEL_DSTR_RAND: 0 +ION_TEMP: 2400 +NPH_SCALE_VECS: 1 2 3 +NPH_SCALE_CONSTRAINTS: none +NPH_ANGLES: 1 +NPH_BMASS: 0.5 +TARGET_STRESS: 0.1 0.1 0.1 0 0 0 GPa +MAXIT_SCF: 100 +MINIT_SCF: 2 +MAXIT_POISSON: 3000 +TOL_SCF: 1.00E-06 +POISSON_SOLVER: AAR +TOL_POISSON: 1.00E-08 +TOL_LANCZOS: 1.00E-02 +TOL_PSEUDOCHARGE: 1.00E-09 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +TOL_PRECOND: 2.25E-05 +PRECOND_KERKER_KTF: 1 +PRECOND_KERKER_THRESH: 0 +MIXING_PARAMETER: 1 +MIXING_HISTORY: 7 +PULAY_FREQUENCY: 1 +PULAY_RESTART: 0 +REFERENCE_CUTOFF: 0.5 +RHO_TRIGGER: 4 +NUM_CHEFSI: 1 +FIX_RAND: 0 +VERBOSITY: 1 +PRINT_FORCES: 1 +PRINT_ATOMS: 1 +PRINT_EIGEN: 0 +PRINT_DENSITY: 0 +PRINT_MDOUT: 1 +PRINT_VELS: 1 +PRINT_RESTART: 1 +PRINT_RESTART_FQ: 1 +PRINT_ENERGY_DENSITY: 0 +OUTPUT_FILE: Al18C2_NPH_full_flex +*************************************************************************** + Cell +*************************************************************************** +Lattice vectors (Bohr): +18.897259886000001 0.000000000000000 0.000000000000000 +0.000000000000000 18.897259886000001 0.000000000000000 +0.000000000000000 0.000000000000000 18.897259886000001 +Volume: 6.7483330373E+03 (Bohr^3) +Density: 7.5528236408E-02 (amu/Bohr^3), 8.4635982984E-01 (g/cc) +*************************************************************************** + Parallelization +*************************************************************************** +NP_SPIN_PARAL: 1 +NP_KPOINT_PARAL: 1 +NP_BAND_PARAL: 20 +NP_DOMAIN_PARAL: 1 1 3 +NP_DOMAIN_PHI_PARAL: 3 4 5 +EIG_SERIAL_MAXNS: 1500 +*************************************************************************** + Initialization +*************************************************************************** +Number of processors : 60 +Mesh spacing : 0.149978 (Bohr) +Number of symmetry adapted k-points: 1 +Output printed to : Al18C2_NPH_full_flex.out +MD output printed to : Al18C2_NPH_full_flex.aimd +Total number of atom types : 2 +Total number of atoms : 20 +Total number of electrons : 62 +Atom type 1 (valence electrons) : Al 3 +Pseudopotential : ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +Atomic mass : 26.9815385 +Pseudocharge radii of atom type 1 : 6.75 6.75 6.75 (x, y, z dir) +Number of atoms of type 1 : 18 +Atom type 2 (valence electrons) : C 4 +Pseudopotential : ../../../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 +Atomic mass : 12.011 +Pseudocharge radii of atom type 2 : 6.75 6.75 6.75 (x, y, z dir) +Number of atoms of type 2 : 2 +Estimated total memory usage : 8.98 GB +Estimated memory per processor : 153.34 MB +=================================================================== + Self Consistent Field (SCF#1) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.5861820497E+00 1.736E-01 38.613 +2 -2.6244864497E+00 5.142E-01 11.518 +3 -2.6150746774E+00 1.241E-01 11.205 +4 -2.6174340406E+00 2.737E-01 11.268 +5 -2.6157559179E+00 6.082E-02 11.235 +6 -2.6157658314E+00 5.247E-02 11.154 +7 -2.6157288088E+00 3.444E-02 11.001 +8 -2.6157105522E+00 5.104E-03 10.973 +9 -2.6157140246E+00 7.046E-03 10.928 +10 -2.6157143798E+00 1.055E-03 10.809 +11 -2.6157148702E+00 3.967E-04 10.706 +12 -2.6157149854E+00 3.712E-04 10.670 +13 -2.6157150307E+00 1.142E-04 10.477 +14 -2.6157150409E+00 1.017E-04 10.350 +15 -2.6157150418E+00 4.235E-05 10.290 +16 -2.6157150404E+00 1.414E-05 10.260 +17 -2.6157150409E+00 7.633E-06 10.166 +18 -2.6157150426E+00 3.597E-06 10.124 +19 -2.6157150421E+00 2.677E-06 9.931 +20 -2.6157150432E+00 9.850E-07 9.804 +Total number of SCF: 20 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157150432E+00 (Ha/atom) +Total free energy : -5.2314300865E+01 (Ha) +Band structure energy : -9.0955811152E+00 (Ha) +Exchange correlation energy : -2.0462214341E+01 (Ha) +Self and correction energy : -7.6945325391E+01 (Ha) +-Entropy*kb*T : -1.4408986225E-01 (Ha) +Fermi level : -2.8343926105E-02 (Ha) +RMS force : 1.0663882766E-02 (Ha/Bohr) +Maximum force : 1.3273889305E-02 (Ha/Bohr) +Time for force calculation : 0.205 (sec) +Pressure : -5.4252879222E+00 (GPa) +Maximum stress : 5.7978356605E+00 (GPa) +Time for stress calculation : 0.475 (sec) +MD step time : 245.475 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8969065154767 18.896860912135 18.8968176390464 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149975 (Bohr) +Mesh spacing in y-direction : 0.149975 (Bohr) +Mesh spacing in z direction : 0.149975 (Bohr) +=================================================================== + Self Consistent Field (SCF#2) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159404318E+00 3.756E-02 11.491 +2 -2.6165102230E+00 1.875E-01 11.289 +3 -2.6157893011E+00 5.313E-02 11.262 +4 -2.6159219462E+00 9.180E-02 11.267 +5 -2.6157320727E+00 3.539E-03 11.136 +6 -2.6157309553E+00 2.086E-03 11.013 +7 -2.6157310449E+00 1.027E-03 10.963 +8 -2.6157313300E+00 5.638E-04 10.923 +9 -2.6157315457E+00 3.360E-04 10.916 +10 -2.6157316819E+00 1.553E-04 10.779 +11 -2.6157317292E+00 9.866E-05 10.500 +12 -2.6157317366E+00 7.316E-05 10.375 +13 -2.6157317376E+00 5.168E-05 10.350 +14 -2.6157317384E+00 1.384E-05 10.373 +15 -2.6157317388E+00 7.884E-06 10.305 +16 -2.6157317386E+00 3.295E-06 10.245 +17 -2.6157317401E+00 1.977E-06 10.101 +18 -2.6157317420E+00 9.229E-07 10.001 +Total number of SCF: 18 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157317420E+00 (Ha/atom) +Total free energy : -5.2314634839E+01 (Ha) +Band structure energy : -9.0962763929E+00 (Ha) +Exchange correlation energy : -2.0462672572E+01 (Ha) +Self and correction energy : -7.6945325713E+01 (Ha) +-Entropy*kb*T : -1.4398192945E-01 (Ha) +Fermi level : -2.8366310091E-02 (Ha) +RMS force : 1.0677796807E-02 (Ha/Bohr) +Maximum force : 1.3506056209E-02 (Ha/Bohr) +Time for force calculation : 0.203 (sec) +Pressure : -5.4249334695E+00 (GPa) +Maximum stress : 5.8015361227E+00 (GPa) +Time for stress calculation : 0.474 (sec) +MD step time : 196.667 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8962003205166 18.8960627251324 18.8959329695506 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.14997 (Bohr) +Mesh spacing in y-direction : 0.149969 (Bohr) +Mesh spacing in z direction : 0.149968 (Bohr) +=================================================================== + Self Consistent Field (SCF#3) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159827488E+00 3.827E-02 11.541 +2 -2.6165897985E+00 1.909E-01 11.290 +3 -2.6158302182E+00 5.423E-02 11.142 +4 -2.6159643732E+00 9.269E-02 11.267 +5 -2.6157708339E+00 3.593E-03 11.103 +6 -2.6157696528E+00 2.166E-03 10.873 +7 -2.6157697259E+00 1.040E-03 10.955 +8 -2.6157700215E+00 5.746E-04 10.798 +9 -2.6157702485E+00 3.493E-04 10.815 +10 -2.6157703926E+00 1.600E-04 10.775 +11 -2.6157704428E+00 1.056E-04 10.480 +12 -2.6157704511E+00 7.685E-05 10.364 +13 -2.6157704517E+00 5.433E-05 10.259 +14 -2.6157704527E+00 1.389E-05 10.267 +15 -2.6157704531E+00 7.974E-06 10.269 +16 -2.6157704531E+00 3.291E-06 10.197 +17 -2.6157704543E+00 1.932E-06 10.091 +18 -2.6157704560E+00 8.188E-07 9.864 +Total number of SCF: 18 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157704560E+00 (Ha/atom) +Total free energy : -5.2315409119E+01 (Ha) +Band structure energy : -9.0970632609E+00 (Ha) +Exchange correlation energy : -2.0463873095E+01 (Ha) +Self and correction energy : -7.6945326815E+01 (Ha) +-Entropy*kb*T : -1.4380745586E-01 (Ha) +Fermi level : -2.8396306736E-02 (Ha) +RMS force : 1.0737064696E-02 (Ha/Bohr) +Maximum force : 1.3774841143E-02 (Ha/Bohr) +Time for force calculation : 0.203 (sec) +Pressure : -5.4235080230E+00 (GPa) +Maximum stress : 5.8052528594E+00 (GPa) +Time for stress calculation : 0.473 (sec) +MD step time : 195.710 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8951420173024 18.8948652817942 18.8946057103804 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149961 (Bohr) +Mesh spacing in y-direction : 0.149959 (Bohr) +Mesh spacing in z direction : 0.149957 (Bohr) +=================================================================== + Self Consistent Field (SCF#4) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6157144117E+00 3.540E-03 10.836 +2 -2.6158302631E+00 4.982E-03 10.642 +3 -2.6158324141E+00 9.608E-03 10.728 +4 -2.6158304527E+00 1.307E-03 10.322 +5 -2.6158305102E+00 2.116E-03 10.362 +6 -2.6158304396E+00 1.048E-04 10.332 +7 -2.6158304369E+00 4.632E-05 10.229 +8 -2.6158304374E+00 3.510E-05 10.398 +9 -2.6158304384E+00 2.182E-05 10.274 +10 -2.6158304384E+00 8.278E-06 10.167 +11 -2.6158304395E+00 6.202E-06 10.099 +12 -2.6158304402E+00 8.683E-06 9.976 +13 -2.6158304393E+00 3.676E-06 9.850 +14 -2.6158304414E+00 7.345E-07 9.807 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6158304414E+00 (Ha/atom) +Total free energy : -5.2316608828E+01 (Ha) +Band structure energy : -9.0979071311E+00 (Ha) +Exchange correlation energy : -2.0465827220E+01 (Ha) +Self and correction energy : -7.6945327854E+01 (Ha) +-Entropy*kb*T : -1.4356457816E-01 (Ha) +Fermi level : -2.8433888321E-02 (Ha) +RMS force : 1.0849374650E-02 (Ha/Bohr) +Maximum force : 1.4075715560E-02 (Ha/Bohr) +Time for force calculation : 0.203 (sec) +Pressure : -5.4210356321E+00 (GPa) +Maximum stress : 5.8090118778E+00 (GPa) +Time for stress calculation : 0.474 (sec) +MD step time : 146.964 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8937324891486 18.8932687352935 18.8928357026158 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.14995 (Bohr) +Mesh spacing in y-direction : 0.149947 (Bohr) +Mesh spacing in z direction : 0.149943 (Bohr) +=================================================================== + Self Consistent Field (SCF#5) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6157976185E+00 3.478E-03 10.821 +2 -2.6159105447E+00 2.682E-03 10.683 +3 -2.6159152138E+00 1.535E-02 10.717 +4 -2.6159112697E+00 1.861E-03 10.438 +5 -2.6159112265E+00 1.116E-03 10.394 +6 -2.6159112060E+00 1.083E-04 10.342 +7 -2.6159112026E+00 5.162E-05 10.290 +8 -2.6159112030E+00 3.363E-05 10.363 +9 -2.6159112039E+00 1.966E-05 10.314 +10 -2.6159112042E+00 9.338E-06 10.198 +11 -2.6159112052E+00 4.120E-06 10.164 +12 -2.6159112067E+00 2.317E-06 9.891 +13 -2.6159112075E+00 3.967E-06 9.759 +14 -2.6159112067E+00 2.027E-06 9.911 +15 -2.6159112073E+00 6.982E-07 9.812 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6159112073E+00 (Ha/atom) +Total free energy : -5.2318224147E+01 (Ha) +Band structure energy : -9.0987731545E+00 (Ha) +Exchange correlation energy : -2.0468545671E+01 (Ha) +Self and correction energy : -7.6945328251E+01 (Ha) +-Entropy*kb*T : -1.4325086366E-01 (Ha) +Fermi level : -2.8477847074E-02 (Ha) +RMS force : 1.1011206891E-02 (Ha/Bohr) +Maximum force : 1.4403117275E-02 (Ha/Bohr) +Time for force calculation : 0.203 (sec) +Pressure : -5.4174938601E+00 (GPa) +Maximum stress : 5.8127932710E+00 (GPa) +Time for stress calculation : 0.474 (sec) +MD step time : 157.130 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8919727868156 18.8912734399755 18.8906227992354 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149936 (Bohr) +Mesh spacing in y-direction : 0.149931 (Bohr) +Mesh spacing in z direction : 0.149926 (Bohr) +=================================================================== + Self Consistent Field (SCF#6) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6158987597E+00 3.482E-03 10.827 +2 -2.6160118044E+00 1.081E-03 10.557 +3 -2.6160131915E+00 5.611E-03 10.525 +4 -2.6160126227E+00 1.482E-03 10.469 +5 -2.6160126748E+00 2.010E-03 10.448 +6 -2.6160125992E+00 1.311E-04 10.430 +7 -2.6160125955E+00 5.160E-05 10.345 +8 -2.6160125954E+00 3.557E-05 10.365 +9 -2.6160125967E+00 2.312E-05 10.344 +10 -2.6160125969E+00 9.511E-06 10.271 +11 -2.6160125976E+00 4.875E-06 10.235 +12 -2.6160125990E+00 2.433E-06 9.924 +13 -2.6160126001E+00 5.649E-06 9.846 +14 -2.6160125994E+00 1.696E-06 9.887 +15 -2.6160125996E+00 4.064E-07 9.784 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6160125996E+00 (Ha/atom) +Total free energy : -5.2320251992E+01 (Ha) +Band structure energy : -9.0997105111E+00 (Ha) +Exchange correlation energy : -2.0472023597E+01 (Ha) +Self and correction energy : -7.6945328068E+01 (Ha) +-Entropy*kb*T : -1.4286367913E-01 (Ha) +Fermi level : -2.8528230831E-02 (Ha) +RMS force : 1.1208928991E-02 (Ha/Bohr) +Maximum force : 1.4752589477E-02 (Ha/Bohr) +Time for force calculation : 0.203 (sec) +Pressure : -5.4128610972E+00 (GPa) +Maximum stress : 5.8165587944E+00 (GPa) +Time for stress calculation : 0.468 (sec) +MD step time : 157.498 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8898641287178 18.888879954704 18.8879668704988 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.14992 (Bohr) +Mesh spacing in y-direction : 0.149912 (Bohr) +Mesh spacing in z direction : 0.149904 (Bohr) +=================================================================== + Self Consistent Field (SCF#7) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6160208645E+00 3.484E-03 10.858 +2 -2.6161355867E+00 1.033E-03 10.611 +3 -2.6161368640E+00 4.869E-03 10.504 +4 -2.6161364285E+00 1.405E-03 10.406 +5 -2.6161365014E+00 2.234E-03 10.384 +6 -2.6161364092E+00 1.437E-04 10.408 +7 -2.6161364060E+00 5.777E-05 10.297 +8 -2.6161364056E+00 4.039E-05 10.347 +9 -2.6161364075E+00 2.681E-05 10.377 +10 -2.6161364078E+00 1.044E-05 10.208 +11 -2.6161364082E+00 5.261E-06 10.149 +12 -2.6161364096E+00 2.285E-06 9.881 +13 -2.6161364105E+00 3.404E-06 9.853 +14 -2.6161364110E+00 1.864E-06 9.858 +15 -2.6161364109E+00 4.143E-07 9.746 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6161364109E+00 (Ha/atom) +Total free energy : -5.2322728217E+01 (Ha) +Band structure energy : -9.1007508688E+00 (Ha) +Exchange correlation energy : -2.0476270511E+01 (Ha) +Self and correction energy : -7.6945327755E+01 (Ha) +-Entropy*kb*T : -1.4240043406E-01 (Ha) +Fermi level : -2.8585266579E-02 (Ha) +RMS force : 1.1432072170E-02 (Ha/Bohr) +Maximum force : 1.5119212406E-02 (Ha/Bohr) +Time for force calculation : 0.203 (sec) +Pressure : -5.4072300627E+00 (GPa) +Maximum stress : 5.8204135410E+00 (GPa) +Time for stress calculation : 0.468 (sec) +MD step time : 156.970 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8874078929007 18.886089038286 18.8848677978964 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.1499 (Bohr) +Mesh spacing in y-direction : 0.14989 (Bohr) +Mesh spacing in z direction : 0.14988 (Bohr) +=================================================================== + Self Consistent Field (SCF#8) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6161672504E+00 3.495E-03 10.846 +2 -2.6162824277E+00 1.337E-03 10.656 +3 -2.6162845722E+00 8.573E-03 10.551 +4 -2.6162832910E+00 1.416E-03 10.445 +5 -2.6162833330E+00 1.806E-03 10.452 +6 -2.6162832689E+00 1.372E-04 10.437 +7 -2.6162832652E+00 5.037E-05 10.340 +8 -2.6162832653E+00 3.514E-05 10.370 +9 -2.6162832661E+00 2.213E-05 10.392 +10 -2.6162832668E+00 9.732E-06 10.277 +11 -2.6162832672E+00 4.527E-06 10.228 +12 -2.6162832687E+00 3.223E-06 9.865 +13 -2.6162832683E+00 9.562E-06 9.919 +14 -2.6162832691E+00 1.035E-06 9.994 +15 -2.6162832688E+00 5.095E-07 9.834 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6162832688E+00 (Ha/atom) +Total free energy : -5.2325665377E+01 (Ha) +Band structure energy : -9.1018942119E+00 (Ha) +Exchange correlation energy : -2.0481299823E+01 (Ha) +Self and correction energy : -7.6945327720E+01 (Ha) +-Entropy*kb*T : -1.4186006652E-01 (Ha) +Fermi level : -2.8648345291E-02 (Ha) +RMS force : 1.1673715041E-02 (Ha/Bohr) +Maximum force : 1.5578297591E-02 (Ha/Bohr) +Time for force calculation : 0.203 (sec) +Pressure : -5.4005752888E+00 (GPa) +Maximum stress : 5.8243803142E+00 (GPa) +Time for stress calculation : 0.467 (sec) +MD step time : 157.569 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8846056217791 18.8829016543586 18.8813254750943 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149878 (Bohr) +Mesh spacing in y-direction : 0.149864 (Bohr) +Mesh spacing in z direction : 0.149852 (Bohr) +=================================================================== + Self Consistent Field (SCF#9) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6163352686E+00 3.523E-03 10.800 +2 -2.6164518888E+00 2.543E-03 10.743 +3 -2.6164559229E+00 1.328E-02 10.741 +4 -2.6164528387E+00 3.076E-03 10.520 +5 -2.6164526729E+00 9.877E-04 10.432 +6 -2.6164526622E+00 1.193E-04 10.426 +7 -2.6164526605E+00 5.733E-05 10.333 +8 -2.6164526603E+00 3.694E-05 10.404 +9 -2.6164526619E+00 2.143E-05 10.350 +10 -2.6164526621E+00 9.521E-06 10.224 +11 -2.6164526630E+00 4.404E-06 10.215 +12 -2.6164526645E+00 2.291E-06 9.962 +13 -2.6164526638E+00 1.166E-06 9.851 +14 -2.6164526661E+00 1.910E-06 9.890 +15 -2.6164526669E+00 7.377E-07 9.773 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6164526669E+00 (Ha/atom) +Total free energy : -5.2329053337E+01 (Ha) +Band structure energy : -9.1031404402E+00 (Ha) +Exchange correlation energy : -2.0487118600E+01 (Ha) +Self and correction energy : -7.6945328009E+01 (Ha) +-Entropy*kb*T : -1.4124205605E-01 (Ha) +Fermi level : -2.8716533202E-02 (Ha) +RMS force : 1.1928505061E-02 (Ha/Bohr) +Maximum force : 1.6340573831E-02 (Ha/Bohr) +Time for force calculation : 0.203 (sec) +Pressure : -5.3928172346E+00 (GPa) +Maximum stress : 5.8284027112E+00 (GPa) +Time for stress calculation : 0.471 (sec) +MD step time : 157.656 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8814590293939 18.8793189805389 18.8773398156494 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149853 (Bohr) +Mesh spacing in y-direction : 0.149836 (Bohr) +Mesh spacing in z direction : 0.14982 (Bohr) +=================================================================== + Self Consistent Field (SCF#10) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6165266040E+00 3.541E-03 10.791 +2 -2.6166432615E+00 2.804E-03 10.740 +3 -2.6166474144E+00 1.346E-02 10.687 +4 -2.6166442673E+00 3.426E-03 10.526 +5 -2.6166440538E+00 9.493E-04 10.387 +6 -2.6166440462E+00 1.217E-04 10.414 +7 -2.6166440448E+00 5.894E-05 10.345 +8 -2.6166440452E+00 3.748E-05 10.400 +9 -2.6166440465E+00 2.144E-05 10.361 +10 -2.6166440467E+00 9.557E-06 10.251 +11 -2.6166440474E+00 4.473E-06 10.214 +12 -2.6166440484E+00 2.223E-06 9.915 +13 -2.6166440482E+00 9.037E-07 9.895 +Total number of SCF: 13 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6166440482E+00 (Ha/atom) +Total free energy : -5.2332880963E+01 (Ha) +Band structure energy : -9.1045250068E+00 (Ha) +Exchange correlation energy : -2.0493725561E+01 (Ha) +Self and correction energy : -7.6945328589E+01 (Ha) +-Entropy*kb*T : -1.4054700708E-01 (Ha) +Fermi level : -2.8789719248E-02 (Ha) +RMS force : 1.2192324520E-02 (Ha/Bohr) +Maximum force : 1.7156458048E-02 (Ha/Bohr) +Time for force calculation : 0.204 (sec) +Pressure : -5.3839210622E+00 (GPa) +Maximum stress : 5.8324867002E+00 (GPa) +Time for stress calculation : 0.471 (sec) +MD step time : 138.193 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8779700046351 18.8753424157612 18.8729107559786 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149825 (Bohr) +Mesh spacing in y-direction : 0.149804 (Bohr) +Mesh spacing in z direction : 0.149785 (Bohr) +=================================================================== + Self Consistent Field (SCF#11) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6167389494E+00 3.544E-03 10.842 +2 -2.6168564641E+00 1.072E-03 10.612 +3 -2.6168578137E+00 4.816E-03 10.490 +4 -2.6168574558E+00 1.420E-03 10.507 +5 -2.6168575250E+00 2.000E-03 10.402 +6 -2.6168574398E+00 2.303E-04 10.391 +7 -2.6168574358E+00 5.716E-05 10.359 +8 -2.6168574359E+00 3.810E-05 10.339 +9 -2.6168574377E+00 2.592E-05 10.485 +10 -2.6168574380E+00 1.243E-05 10.290 +11 -2.6168574381E+00 3.894E-06 10.230 +12 -2.6168574397E+00 2.787E-06 9.979 +13 -2.6168574390E+00 3.325E-06 9.767 +14 -2.6168574394E+00 2.908E-06 9.928 +15 -2.6168574403E+00 4.618E-07 9.823 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6168574403E+00 (Ha/atom) +Total free energy : -5.2337148806E+01 (Ha) +Band structure energy : -9.1060776771E+00 (Ha) +Exchange correlation energy : -2.0501126674E+01 (Ha) +Self and correction energy : -7.6945329605E+01 (Ha) +-Entropy*kb*T : -1.3977322595E-01 (Ha) +Fermi level : -2.8867521787E-02 (Ha) +RMS force : 1.2461982717E-02 (Ha/Bohr) +Maximum force : 1.8026691709E-02 (Ha/Bohr) +Time for force calculation : 0.207 (sec) +Pressure : -5.3738652095E+00 (GPa) +Maximum stress : 5.8366356380E+00 (GPa) +Time for stress calculation : 0.473 (sec) +*************************************************************************** + Timing info +*************************************************************************** +Total walltime : 1869.818 sec +___________________________________________________________________________ + +*************************************************************************** +* Material Physics & Mechanics Group, Georgia Tech * +* PI: Phanish Suryanarayana * +* List of contributors: See the documentation * +* Citation: See README.md or the documentation for details * +* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * +* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * +*************************************************************************** + diff --git a/tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.inpt b/tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.inpt new file mode 100644 index 00000000..4aa8942a --- /dev/null +++ b/tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.inpt @@ -0,0 +1,45 @@ +# nprocs: 48 +LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 +LATVEC: +1 0.0 0.0 +0.0 1.0 0.0 +0.0 0.0 1.0 +MESH_SPACING: 0.25 +BC: P P P +KPOINT_GRID: 1 1 1 +EXCHANGE_CORRELATION: GGA_PBE +TOL_SCF: 1e-6 +# TOL_POISSON: 1e-7 +# TOL_PSEUDOCHARGE: 1e-5 +MIXING_PARAMETER: 1.0 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +PRECOND_KERKER_THRESH: 0 + +# MD +MD_FLAG: 1 # 1 = MD, 0 = no MD (default) +ION_TEMP: 2400 # kelvin +# ION_TEMP_END: 1120 +MD_METHOD: NPH # NVE, NVT_NH (Nose-Hoover), NVK_G (Gaussian) +#QMASS: 1600 # mass for NH thermostat +MD_TIMESTEP: 1 # fs +MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whichever comes first +#TWTIME: 1400 +RESTART_FLAG: 0 # 1 = restart MD from .restart file if present, 0 = start new +#ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) +EXTERNAL_PRESSURE: 0.1 GPa +#EXTERNAL_STRESS: 0 0 0 0 0 0 +#NPT_NP_QMASS: 20000 +NPH_BMASS: 0.5 +NPH_ANGLES: 1 +#NPT_SCALE_CONSTRAINTS: 12 + +NSTATES: 80 + +# outputs +# CALC_PRES: 1 +CALC_STRESS: 1 # whether this selection changes the result of NPT? +PRINT_ATOMS: 1 +# PRINT_VELS: 1 +PRINT_FORCES: 1 +PRINT_MDOUT: 1 # print MD output to .aimd file diff --git a/tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.ion b/tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.ion similarity index 100% rename from tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.ion rename to tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.ion diff --git a/tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.refaimd b/tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.refaimd new file mode 100644 index 00000000..5d16b44e --- /dev/null +++ b/tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.refaimd @@ -0,0 +1,1157 @@ +:Description: + +:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr +:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu + where atu is the atomic unit of time, hbar/Ha +:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr +:Desc_MDTM: MD time. Unit=second +:Desc_TEL: Electronic temperature. Unit=Kelvin +:Desc_TIO: Ionic temperature. Unit=Kelvin +:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom +:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom +:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom + where N = number of particles, k = Boltzmann constant +:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom +:Desc_UEN: Internal energy. Unit=Ha/atom +:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom +:Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree +:Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 +:Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 +:Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during NPH ensemble (has same magnitude as initial LatVec). Unit = Bohr +:Desc_NPH_HAMIL: Hamiltonian of the NPH system, formula (10) in (E. Hernandez, 2001) with M_s (thermostat Mass) = 0 and S = 1, so no thermostat contribution. Unit = Ha +:Desc_NPH_Enthalpy: Enthalpy of the NPH system (or generalized enthalpy in case of anisotropic stress). This quantity is same as NPH Hamiltonian (NPH_HAMIL) plus the initial NPH hamiltonian. Unit = Ha +:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa +:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa +:Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa +:Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa +:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa + where N = number of particles, k = Boltzmann constant, V = volume +:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr + + + + +:MDSTEP: 1 +:MDTM: 42.96 +:TWIST: 0 +:TEL: 2400 +:TIO: 2400.33436319538 +:TEN: -2.6048803829E+00 +:KEN: 1.0832004430E-02 +:KENIG: 1.1402109926E-02 +:FEN: -2.6157123874E+00 +:UEN: -2.6085116861E+00 +:TSEN: -7.2007012654E-03 +:NPH_HAMIL: 3.9148017798E-05 +:NPH_ENTHALPY: -5.2074661570E+01 +:R: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 6.2990803296E+00 + 0.0000000000E+00 0.0000000000E+00 1.2598160659E+01 + 0.0000000000E+00 6.2990803296E+00 0.0000000000E+00 + 0.0000000000E+00 6.2990803296E+00 6.2990803296E+00 + 0.0000000000E+00 6.2990803296E+00 1.2598160659E+01 + 0.0000000000E+00 1.2598160659E+01 0.0000000000E+00 + 0.0000000000E+00 1.2598160659E+01 6.2990803296E+00 + 0.0000000000E+00 1.2598160659E+01 1.2598160659E+01 + 6.2990803296E+00 0.0000000000E+00 0.0000000000E+00 + 6.2990803296E+00 0.0000000000E+00 6.2990803296E+00 + 6.2990803296E+00 0.0000000000E+00 1.2598160659E+01 + 6.2990803296E+00 6.2990803296E+00 0.0000000000E+00 + 6.2990803296E+00 6.2990803296E+00 6.2990803296E+00 + 6.2990803296E+00 6.2990803296E+00 1.2598160659E+01 + 6.2990803296E+00 1.2598160659E+01 0.0000000000E+00 + 6.2990803296E+00 1.2598160659E+01 6.2990803296E+00 + 6.2990803296E+00 1.2598160659E+01 1.2598160659E+01 + 1.2598160659E+01 0.0000000000E+00 0.0000000000E+00 + 1.2598160659E+01 0.0000000000E+00 6.2990803296E+00 +:V: + -6.7710426749E-06 6.8757511011E-04 4.3936035707E-04 + 3.7347487726E-05 -1.5727035383E-04 5.1719494079E-04 + 6.4986539326E-04 -4.5410617125E-04 -3.0784834058E-04 + -3.2394291761E-04 -1.3629799369E-04 -4.4900352153E-04 + 2.9184758164E-04 4.0511649994E-04 -3.3972574526E-05 + -1.6699277297E-04 3.6969211830E-04 -5.9863718346E-05 + -7.8895390279E-04 -5.9299432237E-04 2.6594936895E-04 + 4.8089642926E-05 1.3106985215E-04 3.9308987966E-04 + 4.6023631429E-04 -4.7428025267E-04 1.4680482757E-04 + -4.4619399954E-04 -2.7196367677E-05 -6.1811109029E-04 + 2.1182548457E-05 1.9314809303E-05 -3.0795928476E-04 + 9.2716438501E-05 -4.7512761661E-04 4.3478005703E-04 + 5.4429853500E-04 -4.6901369639E-05 3.8053261056E-04 + 7.8083445741E-04 3.4892960494E-04 -5.1049131496E-05 + -7.0230025937E-04 5.7124825763E-04 -2.9842626635E-04 + 5.5675794584E-05 -8.3790414271E-04 -5.9249441992E-05 + -3.2642657193E-04 5.9659856369E-04 -2.8121297157E-05 + -1.4748598978E-04 9.7058079243E-06 -4.3002564371E-04 + 1.9870074724E-04 1.8287976132E-04 2.9481009460E-04 + -3.6274818038E-04 -4.1742870461E-05 -1.4673114071E-04 +:F: + -3.2347004230E-03 1.4922635353E-07 3.2354355968E-04 + -3.2062773957E-03 1.4972711078E-07 -3.2974094264E-04 + 1.1731210119E-02 1.4753885032E-07 3.4367413345E-06 + 1.2517239085E-02 -2.4489184783E-04 1.2723397345E-04 + 1.2519610684E-02 -2.4352279640E-04 -1.2566375609E-04 + 1.3274649373E-02 -5.4416449743E-05 -1.7583705183E-06 + 1.2517191044E-02 2.4475180701E-04 1.2723475999E-04 + 1.2519574722E-02 2.4338203657E-04 -1.2566912233E-04 + 1.3274638112E-02 5.4267761352E-05 -1.7542358216E-06 + 3.2382709951E-03 1.4904425863E-07 3.2360159476E-04 + 3.2088403709E-03 1.5179838778E-07 -3.2615818622E-04 + -1.1732258500E-02 1.4910299194E-07 2.3773022109E-06 + -1.2517472044E-02 -2.4412888634E-04 1.2708060857E-04 + -1.2518306643E-02 -2.4485754206E-04 -1.2710343272E-04 + -1.3273359327E-02 -5.5819788136E-05 -3.0395985389E-07 + -1.2517426494E-02 2.4398893659E-04 1.2708406049E-04 + -1.2518271745E-02 2.4471308388E-04 -1.2710753913E-04 + -1.3273346564E-02 5.5668955639E-05 -3.0204481673E-07 + -5.4987593619E-06 -8.7907876122E-09 1.1878554769E-02 + -4.3066099801E-06 -2.2917683534E-08 -1.1874585779E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483330373E+03 +:LATVEC_SCALE: + 1.8897259886E+01 1.8897259886E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0617040590E-01 -7.6080180098E-02 1.3808688027E-01 + -7.6080180098E-02 7.2214947439E-01 -2.9245138687E-02 + 1.3808688027E-01 -2.9245138687E-02 4.6067149340E-01 +:STRESS: + 4.9561077757E+00 3.2150433858E-07 4.2017154042E-05 + 3.2150433858E-07 5.5315583280E+00 6.9709570893E-08 + 4.2017154042E-05 6.9709570893E-08 5.8022455634E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2499373698E+00 -7.6080501602E-02 1.3804486311E-01 + -7.6080501602E-02 -4.8094088536E+00 -2.9245208397E-02 + 1.3804486311E-01 -2.9245208397E-02 -5.3415740700E+00 +:PRESIO: 6.2966379123E-01 +:PRES: -5.4299705557E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.8003067645E+00 +:PRESIG: 6.6280399077E-01 +:MIND: +Al - Al: 6.2990803296E+00 +C - C: 6.2990803296E+00 +Al - C: 6.2990803296E+00 + + +:MDSTEP: 2 +:MDTM: 31.92 +:TWIST: 0 +:TEL: 2400 +:TIO: 2403.29172612605 +:TEN: -2.6048863328E+00 +:KEN: 1.0845350141E-02 +:KENIG: 1.1416158043E-02 +:FEN: -2.6157316829E+00 +:UEN: -2.6085363518E+00 +:TSEN: -7.1953311622E-03 +:NPH_HAMIL: -9.5443132793E-06 +:NPH_ENTHALPY: -5.2074710263E+01 +:R: + 1.8896569962E+01 2.8424696682E-02 1.8168956410E-02 + 1.4833996014E-03 1.8890357341E+01 6.3203081139E+00 + 2.7072237005E-02 1.8878084422E+01 1.2585139074E+01 + 1.8883749875E+01 6.2933035877E+00 1.8878257503E+01 + 1.2286019627E-02 6.3156891246E+00 6.2975261712E+00 + 1.8890243967E+01 6.3142263629E+00 1.2595390768E+01 + 1.8864499506E+01 1.2573384013E+01 1.0996665228E-02 + 2.2048225481E-03 1.2603315577E+01 6.3151811059E+00 + 1.9263821532E-02 1.2578285232E+01 1.2603934530E+01 + 6.2805827796E+00 1.8895731504E+01 1.8871269940E+01 + 6.2999013143E+00 7.9690385571E-04 6.2861959662E+00 + 6.3025941373E+00 1.8877215378E+01 1.2615839614E+01 + 6.3212424349E+00 6.2970040510E+00 1.5733580170E-02 + 6.3310284110E+00 6.3133663073E+00 6.2968201944E+00 + 6.2697090819E+00 6.3225587726E+00 1.2585528521E+01 + 6.3010608100E+00 1.2563254551E+01 1.8894370092E+01 + 6.2852494458E+00 1.2622560794E+01 6.2977680403E+00 + 6.2926413197E+00 1.2598293488E+01 1.2580088149E+01 + 1.2606138991E+01 7.5603371980E-03 1.2651179975E-02 + 1.2582923495E+01 1.8895133308E+01 6.2924034134E+00 +:V: + -9.5063506640E-06 6.8790817872E-04 4.3971361646E-04 + 3.4775521608E-05 -1.5742007620E-04 5.1706559340E-04 + 6.5974342317E-04 -4.5425633149E-04 -3.0803969898E-04 + -3.1351817853E-04 -1.3660140653E-04 -4.4897748255E-04 + 3.0232686522E-04 4.0503274496E-04 -3.3984253063E-05 + -1.5574625745E-04 3.6992147969E-04 -5.9836882445E-05 + -7.7857446508E-04 -5.9304296729E-04 2.6606470678E-04 + 5.8699825421E-05 1.3131805832E-04 3.9301164397E-04 + 4.7147098300E-04 -4.7434071181E-04 1.4676000226E-04 + -4.4381185806E-04 -2.7035730250E-05 -6.1808276868E-04 + 2.4069115374E-05 1.9167545851E-05 -3.0830185557E-04 + 8.2859078398E-05 -4.7535647037E-04 4.3505516229E-04 + 5.3387333767E-04 -4.6999010700E-05 3.8077598636E-04 + 7.7039588445E-04 3.4868197189E-04 -5.1150237512E-05 + -7.1356059518E-04 5.7146018348E-04 -2.9861500486E-04 + 4.5251970198E-05 -8.3796126977E-04 -5.9083462263E-05 + -3.3703567110E-04 5.9697425990E-04 -2.8159361140E-05 + -1.5872660464E-04 9.7191783494E-06 -4.3014886911E-04 + 1.9931046371E-04 1.8282725746E-04 3.1754511715E-04 + -3.6326643834E-04 -4.1684959987E-05 -1.6943270183E-04 +:F: + -3.2733958848E-03 7.5780296905E-04 4.9208177802E-04 + -2.9151252942E-03 -3.4855114875E-04 -6.6516860100E-06 + 1.1743643925E-02 -3.3562998665E-04 -4.3947917819E-04 + 1.2301836565E-02 -4.6970101682E-04 -4.1075007638E-05 + 1.2401815933E-02 2.3406557470E-05 1.0036936597E-04 + 1.3492774849E-02 5.8182871234E-04 6.8270801980E-05 + 1.2214809658E-02 -3.2946611078E-04 1.3051725474E-04 + 1.2724175404E-02 3.4052714558E-04 -8.2319040157E-05 + 1.3436654469E-02 -1.7500547642E-04 -1.1148445652E-04 + 2.4496718475E-03 3.8413628314E-04 -2.2301342635E-04 + 3.6585235696E-03 -3.5156033302E-04 -4.7174036261E-04 + -1.1726495326E-02 -5.2093619746E-04 6.2851675847E-04 + -1.2312510796E-02 1.3322704744E-05 4.3235551884E-04 + -1.2354040157E-02 -3.6311466855E-04 -1.0863849926E-04 + -1.3488222250E-02 5.3246271931E-04 -4.3449723250E-04 + -1.2287521396E-02 -3.3787142198E-04 2.7179569746E-04 + -1.2710500805E-02 6.1974172767E-04 3.6811986028E-05 + -1.3466027487E-02 -2.4105690142E-05 -2.6937618913E-04 + 6.4737947973E-04 -5.9835355126E-05 1.2195344706E-02 + -5.3744630362E-04 6.2548586400E-05 -1.2167788789E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7479060418E+03 +:LATVEC_SCALE: + 1.8896906079E+01 1.8896860564E+01 1.8896817280E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -6.5496271229E-07 1.0000000000E+00 0.0000000000E+00 + 1.1884020412E-06 -2.5176604531E-07 1.0000000000E+00 +:STRIO: + 7.0590877020E-01 -7.8725118308E-02 1.3854410507E-01 + -7.8725118308E-02 7.2258585804E-01 -2.8783385312E-02 + 1.3854410507E-01 -2.8783385312E-02 4.6294378094E-01 +:STRESS: + 4.9486170582E+00 -1.5746279530E-03 1.6138608481E-03 + -1.5746279530E-03 5.5343902862E+00 5.8808527095E-04 + 1.6138608481E-03 5.8808527095E-04 5.8059573203E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2427082880E+00 -7.7150490355E-02 1.3693024422E-01 + -7.7150490355E-02 -4.8118044282E+00 -2.9371470583E-02 + 1.3693024422E-01 -2.9371470583E-02 -5.3430135393E+00 +:PRESIO: 6.3047946973E-01 +:PRES: -5.4296548882E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7991754185E+00 +:PRESIG: 6.6366259971E-01 +:MIND: +Al - Al: 6.2554964557E+00 +C - C: 6.2798067712E+00 +Al - C: 6.2830257588E+00 + + +:MDSTEP: 3 +:MDTM: 32.52 +:TWIST: 0 +:TEL: 2400 +:TIO: 2410.18982187653 +:TEN: -2.6048949596E+00 +:KEN: 1.0876479222E-02 +:KENIG: 1.1448925497E-02 +:FEN: -2.6157714388E+00 +:UEN: -2.6085847590E+00 +:TSEN: -7.1866797758E-03 +:NPH_HAMIL: -4.1538501705E-05 +:NPH_ENTHALPY: -5.2074742257E+01 +:R: + 1.8895413054E+01 5.6874509090E-02 3.6354167466E-02 + 2.8604117328E-03 1.8883041782E+01 6.3413870679E+00 + 5.4553819068E-02 1.8858495363E+01 1.2571807589E+01 + 1.8870332595E+01 6.2873728004E+00 1.8858811795E+01 + 2.5005719130E-02 6.3321632515E+00 6.2958279619E+00 + 1.8883354507E+01 6.3292555892E+00 1.2592328189E+01 + 1.8831803231E+01 1.2548330547E+01 2.1997382568E-02 + 4.8508037868E-03 1.2608214115E+01 6.3311306652E+00 + 3.9000361156E-02 1.2558134996E+01 1.2609409026E+01 + 6.2620629217E+00 1.8893812178E+01 1.8844830681E+01 + 6.3007390151E+00 1.5799754106E-03 6.2731482131E+00 + 6.3055849885E+00 1.8856750833E+01 1.2633244368E+01 + 6.3428539964E+00 6.2947951306E+00 3.1481419258E-02 + 6.3624314703E+00 6.3275042979E+00 6.2944087548E+00 + 6.2397630668E+00 6.3459183334E+00 1.2572586716E+01 + 6.3025104653E+00 1.2528067013E+01 1.8891047064E+01 + 6.2708586641E+00 1.2646713440E+01 6.2963095132E+00 + 6.2856232985E+00 1.2598155907E+01 1.2561711932E+01 + 1.2613932073E+01 1.5115679407E-02 2.6253687549E-02 + 1.2567404283E+01 1.8892610519E+01 6.2846294491E+00 +:V: + -1.2275807082E-05 6.8889698827E-04 4.4022040367E-04 + 3.2447998009E-05 -1.5786494259E-04 5.1721939333E-04 + 6.6964219208E-04 -4.5470161415E-04 -3.0861034832E-04 + -3.0328555304E-04 -1.3709515234E-04 -4.4910172061E-04 + 3.1271486745E-04 4.0518073867E-04 -3.3807787139E-05 + -1.4432112431E-04 3.7069200919E-04 -5.9750726563E-05 + -7.6846497024E-04 -5.9359465350E-04 2.6618979458E-04 + 6.9483569553E-05 1.3165004944E-04 3.9297807729E-04 + 4.8284811117E-04 -4.7460146858E-04 1.4662412267E-04 + -4.4209610294E-04 -2.6550809661E-05 -6.1852857901E-04 + 2.7335974115E-05 1.8727378533E-05 -3.0877459052E-04 + 7.3009273599E-05 -4.7603445400E-04 4.3586419960E-04 + 5.2363427506E-04 -4.6880988986E-05 3.8128532960E-04 + 7.6011031292E-04 3.4834212043E-04 -5.1241098438E-05 + -7.2501360943E-04 5.7217956880E-04 -2.9917379994E-04 + 3.5021293688E-05 -8.3852780166E-04 -5.8797160420E-05 + -3.4781003650E-04 5.9767445463E-04 -2.8061213776E-05 + -1.7013128851E-04 9.6697352039E-06 -4.3050612014E-04 + 2.0114836019E-04 1.8266862826E-04 3.4092428496E-04 + -3.6479736798E-04 -4.1507305881E-05 -1.9272502489E-04 +:F: + -3.3153473598E-03 1.5257947478E-03 6.6384536872E-04 + -2.6260282576E-03 -6.9422929688E-04 3.1533771162E-04 + 1.1750548648E-02 -6.8026176726E-04 -8.7968349120E-04 + 1.2073375721E-02 -6.9040015818E-04 -2.0605430261E-04 + 1.2288268203E-02 2.8702147631E-04 3.2454829620E-04 + 1.3705827465E-02 1.2148212762E-03 1.4210863692E-04 + 1.1908831992E-02 -9.2112873357E-04 1.3380505963E-04 + 1.2929225866E-02 4.3599487067E-04 -4.1160543085E-05 + 1.3591881595E-02 -3.9921841906E-04 -2.2493023260E-04 + 1.6722607490E-03 7.7378912703E-04 -7.7129998916E-04 + 4.1124398856E-03 -6.9777825162E-04 -6.1858049574E-04 + -1.1717308919E-02 -1.0446774480E-03 1.2490025737E-03 + -1.2097636996E-02 2.7056869816E-04 7.4014999675E-04 + -1.2187829276E-02 -4.8299967788E-04 -9.7958064388E-05 + -1.3699322691E-02 1.1240080841E-03 -8.6653874778E-04 + -1.2059168951E-02 -9.2596299098E-04 4.1724472349E-04 + -1.2895803428E-02 9.8731311824E-04 1.9721397302E-04 + -1.3655919315E-02 -9.4001178535E-05 -5.3364328957E-04 + 1.2914253567E-03 -1.1665134131E-04 1.2552306613E-02 + -1.0697202878E-03 1.2799786487E-04 -1.2495713797E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7470521477E+03 +:LATVEC_SCALE: + 1.8896199009E+01 1.8896061674E+01 1.8895931892E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.9742897051E-06 1.0000000000E+00 0.0000000000E+00 + 3.5559534834E-06 -7.5645593305E-07 9.9999999999E-01 +:STRIO: + 7.0695525379E-01 -8.1508123651E-02 1.3934900917E-01 + -8.1508123651E-02 7.2410387680E-01 -2.8374074308E-02 + 1.3934900917E-01 -2.8374074308E-02 4.6604828115E-01 +:STRESS: + 4.9397212702E+00 -3.2275036639E-03 2.6677456898E-03 + -3.2275036639E-03 5.5351523724E+00 1.6612946903E-03 + 2.6677456898E-03 1.6612946903E-03 5.8097442547E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2327660164E+00 -7.8280619987E-02 1.3668126348E-01 + -7.8280619987E-02 -4.8110484956E+00 -3.0035368999E-02 + 1.3668126348E-01 -3.0035368999E-02 -5.3436959736E+00 +:PRESIO: 6.3236913724E-01 +:PRES: -5.4282059658E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7958368285E+00 +:PRESIG: 6.6565172342E-01 +:MIND: +Al - Al: 6.2118493404E+00 +C - C: 6.2585905481E+00 +Al - C: 6.2666778314E+00 + + +:MDSTEP: 4 +:MDTM: 20.32 +:TWIST: 0 +:TEL: 2400 +:TIO: 2421.06869048323 +:TEN: -2.6049055016E+00 +:KEN: 1.0925572363E-02 +:KENIG: 1.1500602487E-02 +:FEN: -2.6158310739E+00 +:UEN: -2.6086564157E+00 +:TSEN: -7.1746582601E-03 +:NPH_HAMIL: -4.1786822706E-05 +:NPH_ENTHALPY: -5.2074742505E+01 +:R: + 1.8893788444E+01 8.5375509609E-02 5.4561181718E-02 + 4.1409195744E-03 1.8875301249E+01 6.3623278171E+00 + 8.2444245319E-02 1.8838481042E+01 1.2558151056E+01 + 1.8857000922E+01 6.2812802976E+00 1.8838917304E+01 + 3.8154800840E-02 6.3485114749E+00 6.2939934549E+00 + 1.8876599622E+01 6.3441895891E+00 1.2588975440E+01 + 1.8799161666E+01 1.2522980167E+01 3.3002038907E-02 + 7.9448971155E-03 1.2612859404E+01 6.3469299963E+00 + 5.9214521875E-02 1.2537702486E+01 1.2614579920E+01 + 6.2434940411E+00 1.8891515319E+01 1.8817923506E+01 + 6.3016093795E+00 2.3371395334E-03 6.2599322089E+00 + 6.3080532584E+00 1.8835848347E+01 1.2650395935E+01 + 6.3639223086E+00 6.2924625403E+00 4.7253816096E-02 + 6.3932948545E+00 6.3414898031E+00 6.2918463409E+00 + 6.2092356143E+00 6.3691789654E+00 1.2559320449E+01 + 6.3034373395E+00 1.2492578209E+01 1.8887295728E+01 + 6.2559018939E+00 1.2670630773E+01 6.2947103146E+00 + 6.2780198630E+00 1.2597745382E+01 1.2543023136E+01 + 1.2621590530E+01 2.2661429849E-02 4.0835013641E-02 + 1.2551562023E+01 1.8889696581E+01 6.2757330201E+00 +:V: + -1.5082817589E-05 6.9054795120E-04 4.4088347325E-04 + 3.0364058125E-05 -1.5860189950E-04 5.1765350503E-04 + 6.7955691142E-04 -4.5544931713E-04 -3.0955652285E-04 + -2.9325557256E-04 -1.3777540353E-04 -4.4937348022E-04 + 3.2301569237E-04 4.0555702135E-04 -3.3444928985E-05 + -1.3272035288E-04 3.7200000846E-04 -5.9602081708E-05 + -7.5862777735E-04 -5.9466226151E-04 2.6632422502E-04 + 8.0441804268E-05 1.3206455328E-04 3.9298799382E-04 + 4.9436196384E-04 -4.7505769766E-04 1.4639375105E-04 + -4.4103653693E-04 -2.5737502689E-05 -6.1944840401E-04 + 3.0985989506E-05 1.7999078134E-05 -3.0937758278E-04 + 6.3169239559E-05 -4.7716333282E-04 4.3720025082E-04 + 5.1358862648E-04 -4.6548442288E-05 3.8206217182E-04 + 7.4997843867E-04 3.4790909146E-04 -5.1327909153E-05 + -7.3665645384E-04 5.7340809086E-04 -3.0010038105E-04 + 2.4982144784E-05 -8.3960715799E-04 -5.8389608284E-05 + -3.5874421726E-04 5.9869232921E-04 -2.7830146020E-05 + -1.8169770011E-04 9.5663984870E-06 -4.3109282196E-04 + 2.0419766359E-04 1.8240997586E-04 3.6502596816E-04 + -3.6733913025E-04 -4.1204510858E-05 -2.1667693580E-04 +:F: + -3.3618979489E-03 2.2985417418E-03 8.3882366253E-04 + -2.3367315164E-03 -1.0355825433E-03 6.3160724098E-04 + 1.1750764252E-02 -1.0333715697E-03 -1.3134635913E-03 + 1.1831995957E-02 -9.0605613922E-04 -3.6770292605E-04 + 1.2179349834E-02 5.4563569695E-04 5.4642312220E-04 + 1.3915819667E-02 1.8420970394E-03 2.1972238837E-04 + 1.1599896200E-02 -1.5258938645E-03 1.3616281032E-04 + 1.3135068472E-02 5.3003305802E-04 -5.8590146411E-07 + 1.3739269578E-02 -6.1700667821E-04 -3.4274906079E-04 + 9.0779334457E-04 1.1674656038E-03 -1.3175081903E-03 + 4.5686175627E-03 -1.0380775711E-03 -7.6428690238E-04 + -1.1705392831E-02 -1.5698147219E-03 1.8584710080E-03 + -1.1874416411E-02 5.2529925813E-04 1.0489132677E-03 + -1.2020940493E-02 -6.0348551613E-04 -9.4286306619E-05 + -1.3906435398E-02 1.7162057739E-03 -1.2952893552E-03 + -1.1832223500E-02 -1.5158107907E-03 5.6407782590E-04 + -1.3074119992E-02 1.3460505865E-03 3.5320805180E-04 + -1.3842015337E-02 -1.5249978761E-04 -7.9181776232E-04 + 1.9264239058E-03 -1.7001009548E-04 1.2950914643E-02 + -1.6008253455E-03 1.9628051958E-04 -1.2860634025E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7457716446E+03 +:LATVEC_SCALE: + 1.8895139402E+01 1.8894863173E+01 1.8894603548E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -3.9681152193E-06 9.9999999999E-01 0.0000000000E+00 + 7.1012323805E-06 -1.5199374172E-06 9.9999999997E-01 +:STRIO: + 7.0931030161E-01 -8.4430891358E-02 1.4051315508E-01 + -8.4430891358E-02 7.2671278823E-01 -2.8018337964E-02 + 1.4051315508E-01 -2.8018337964E-02 4.7000903173E-01 +:STRESS: + 4.9294695349E+00 -4.9738602268E-03 3.1486350393E-03 + -4.9738602268E-03 5.5338626798E+00 3.2129942311E-03 + 3.1486350393E-03 3.2129942311E-03 5.8135818946E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2201592333E+00 -7.9457031131E-02 1.3736452004E-01 + -7.9457031131E-02 -4.8071498916E+00 -3.1231332195E-02 + 1.3736452004E-01 -3.1231332195E-02 -5.3435728629E+00 +:PRESIO: 6.3534404052E-01 +:PRES: -5.4256380365E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7902939959E+00 +:PRESIG: 6.6878320055E-01 +:MIND: +Al - Al: 6.1681166522E+00 +C - C: 6.2353820780E+00 +Al - C: 6.2499771941E+00 + + +:MDSTEP: 5 +:MDTM: 21.56 +:TWIST: 0 +:TEL: 2400 +:TIO: 2435.9663611686 +:TEN: -2.6049168941E+00 +:KEN: 1.0992801178E-02 +:KENIG: 1.1571369661E-02 +:FEN: -2.6159096953E+00 +:UEN: -2.6087504990E+00 +:TSEN: -7.1591963279E-03 +:NPH_HAMIL: 1.0695907449E-05 +:NPH_ENTHALPY: -5.2074690023E+01 +:R: + 1.8891695435E+01 1.1395393320E-01 7.2795658542E-02 + 5.3348573830E-03 1.8867124107E+01 6.3831407896E+00 + 1.1074287188E-01 1.8818029647E+01 1.2544154554E+01 + 1.8843747601E+01 6.2750185676E+00 1.8818568696E+01 + 5.1729169689E-02 6.3647424258E+00 6.2920303241E+00 + 1.8869987584E+01 6.3590497536E+00 1.2585335176E+01 + 1.8766565474E+01 1.2497312462E+01 4.4010487292E-02 + 1.1494120506E-02 1.2617254635E+01 6.3625800691E+00 + 7.9911025398E-02 1.2516980537E+01 1.2619442835E+01 + 6.2248500751E+00 1.8888854597E+01 1.8790529893E+01 + 6.3025285399E+00 3.0564995797E-03 6.2465431354E+00 + 6.3099995786E+00 1.8814490117E+01 1.2667314947E+01 + 6.3844550221E+00 6.2900152311E+00 6.3061102495E-02 + 6.4236240516E+00 6.3553183440E+00 6.2891330427E+00 + 6.1781203570E+00 6.3923606529E+00 1.2545715047E+01 + 6.3038496444E+00 1.2456768292E+01 1.8883121066E+01 + 6.2403733975E+00 1.2694324768E+01 6.2929758610E+00 + 6.2698249057E+00 1.2597059855E+01 1.2524013109E+01 + 1.2629164396E+01 3.0193261282E-02 5.6425874264E-02 + 1.2535355962E+01 1.8886396954E+01 6.2656858500E+00 +:V: + -1.7932231645E-05 6.9286191630E-04 4.4170531013E-04 + 2.8524758897E-05 -1.5962679474E-04 5.1836202704E-04 + 6.8948123219E-04 -4.5650669379E-04 -3.1087198586E-04 + -2.8343833414E-04 -1.3863591084E-04 -4.4978989473E-04 + 3.3323384538E-04 4.0615667137E-04 -3.2897838630E-05 + -1.2094534211E-04 3.7384033133E-04 -5.9388108139E-05 + -7.4906410137E-04 -5.9625593353E-04 2.6646690104E-04 + 9.1575407668E-05 1.3256066338E-04 3.9304139097E-04 + 5.0600598161E-04 -4.7570358812E-04 1.4606506022E-04 + -4.4062107619E-04 -2.4593506573E-05 -6.2083824399E-04 + 3.5020653803E-05 1.6987641647E-05 -3.1010962583E-04 + 5.3341063676E-05 -4.7874331393E-04 4.3905200234E-04 + 5.0374209604E-04 -4.6004350293E-05 3.8310724387E-04 + 7.3999961289E-04 3.4738196315E-04 -5.1416796290E-05 + -7.4848594126E-04 5.7514505081E-04 -3.0139112387E-04 + 1.5132684352E-05 -8.4119856109E-04 -5.7859615651E-05 + -3.6983253447E-04 6.0002079864E-04 -2.7470105131E-05 + -1.9342271226E-04 9.4188771313E-06 -4.3190326950E-04 + 2.0844043687E-04 1.8205819694E-04 3.8993056339E-04 + -3.7088916374E-04 -4.0771307788E-05 -2.4136098868E-04 +:F: + -3.4151355761E-03 3.0683039865E-03 1.0163483115E-03 + -2.0449639241E-03 -1.3712599288E-03 9.3943900990E-04 + 1.1741752419E-02 -1.3951951763E-03 -1.7385701515E-03 + 1.1578616509E-02 -1.1118147395E-03 -5.2573748966E-04 + 1.2075653850E-02 7.9743144814E-04 7.6544339269E-04 + 1.4124476781E-02 2.4626015708E-03 3.0034429016E-04 + 1.1290110716E-02 -2.1415205201E-03 1.3687262851E-04 + 1.3341221029E-02 6.2325309875E-04 4.0605592116E-05 + 1.3877901904E-02 -8.2737358284E-04 -4.6517754822E-04 + 1.5908091237E-04 1.5624766695E-03 -1.8560834911E-03 + 5.0257127052E-03 -1.3723032886E-03 -9.0813191599E-04 + -1.1690361130E-02 -2.0938422333E-03 2.4517462076E-03 + -1.1645050435E-02 7.7540742351E-04 1.3582568596E-03 + -1.1855315297E-02 -7.2548962660E-04 -9.8223759470E-05 + -1.4108972045E-02 2.3059513168E-03 -1.7186284764E-03 + -1.1607379038E-02 -2.1018443298E-03 7.1226388919E-04 + -1.3244956799E-02 1.6966657427E-03 5.0408557706E-04 + -1.4023437728E-02 -1.9923300710E-04 -1.0424619203E-03 + 2.5512883413E-03 -2.1951124928E-04 1.3391786418E-02 + -2.1302431935E-03 2.6729642549E-04 -1.3264177424E-02 +:ANGLES: + 90.000 89.999 90.000 +:VOLUME: 6.7440650149E+03 +:LATVEC_SCALE: + 1.8893728158E+01 1.8893265227E+01 1.8892832084E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -6.6471927506E-06 9.9999999998E-01 0.0000000000E+00 + 1.1831224878E-05 -2.5527464045E-06 9.9999999993E-01 +:STRIO: + 7.1297436111E-01 -8.7496100055E-02 1.4204940834E-01 + -8.7496100055E-02 7.3041969758E-01 -2.7717384006E-02 + 1.4204940834E-01 -2.7717384006E-02 4.7485183778E-01 +:STRESS: + 4.9179570176E+00 -6.8044042122E-03 2.9952929043E-03 + -6.8044042122E-03 5.5305566124E+00 5.2352115945E-03 + 2.9952929043E-03 5.2352115945E-03 5.8174467263E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2049826565E+00 -8.0691695843E-02 1.3905411543E-01 + -8.0691695843E-02 -4.8001369148E+00 -3.2952595601E-02 + 1.3905411543E-01 -3.2952595601E-02 -5.3425948885E+00 +:PRESIO: 6.3941529882E-01 +:PRES: -5.4219867854E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7825714866E+00 +:PRESIG: 6.7306873560E-01 +:MIND: +Al - Al: 6.1242584685E+00 +C - C: 6.2101273704E+00 +Al - C: 6.2328648684E+00 + + +:MDSTEP: 6 +:MDTM: 25.87 +:TWIST: 0 +:TEL: 2400 +:TIO: 2454.91878021767 +:TEN: -2.6049305865E+00 +:KEN: 1.1078327882E-02 +:KENIG: 1.1661397771E-02 +:FEN: -2.6160089143E+00 +:UEN: -2.6088686971E+00 +:TSEN: -7.1402172866E-03 +:NPH_HAMIL: 8.6499514126E-05 +:NPH_ENTHALPY: -5.2074614219E+01 +:R: + 1.8889133268E+01 1.4263590846E-01 9.1063344949E-02 + 6.4522921614E-03 1.8858499093E+01 6.4038361221E+00 + 1.3944883012E-01 1.8797129212E+01 1.2529803474E+01 + 1.8830565286E+01 6.2685804259E+00 1.8797760774E+01 + 6.5724957586E-02 6.3808645379E+00 6.2899461462E+00 + 1.8863526887E+01 6.3738572478E+00 1.2581410160E+01 + 1.8734005438E+01 1.2471306782E+01 5.5022522168E-02 + 1.5505543062E-02 1.2621403073E+01 6.3780818771E+00 + 1.0109438787E-01 1.2495962324E+01 1.2623993242E+01 + 6.2061057169E+00 1.8885843845E+01 1.8762631602E+01 + 6.3035127689E+00 3.7263436397E-03 6.2329762431E+00 + 6.3114248556E+00 1.8792658521E+01 1.2684021479E+01 + 6.4044600646E+00 6.2874620591E+00 7.8913629304E-02 + 6.4534246254E+00 6.3689854295E+00 6.2862686910E+00 + 6.1464112538E+00 6.4154833040E+00 1.2531756036E+01 + 6.3037557435E+00 1.2420617597E+01 1.8878528121E+01 + 6.2242678071E+00 1.2717807223E+01 6.2911113954E+00 + 6.2610326489E+00 1.2596097757E+01 1.2504673471E+01 + 1.2636703031E+01 3.7707147277E-02 7.3060257464E-02 + 1.2518745635E+01 1.8882717483E+01 6.2544566775E+00 +:V: + -2.0830876518E-05 6.9583335732E-04 4.4268751457E-04 + 2.6933236376E-05 -1.6093452928E-04 5.1933780910E-04 + 6.9940753461E-04 -4.5788067198E-04 -3.1254911555E-04 + -2.7384313576E-04 -1.3966716258E-04 -4.5034794708E-04 + 3.4337440307E-04 4.0697363499E-04 -3.2168734635E-05 + -1.0899643224E-04 3.7620638610E-04 -5.9106486129E-05 + -7.3977355680E-04 -5.9838301062E-04 2.6661688996E-04 + 1.0288486331E-04 1.3313777602E-04 3.9313831611E-04 + 5.1777242240E-04 -4.7653210894E-04 1.4563437465E-04 + -4.4083554117E-04 -2.3118608131E-05 -6.2268984630E-04 + 3.9440836633E-05 1.5697661721E-05 -3.1096818211E-04 + 4.3526375862E-05 -4.8077197632E-04 4.4140349985E-04 + 4.9409889840E-04 -4.5252917377E-05 3.8442071171E-04 + 7.3017174213E-04 3.4675959357E-04 -5.1514550510E-05 + -7.6049852976E-04 5.7738710366E-04 -3.0304056748E-04 + 5.4706750249E-06 -8.4329768886E-04 -5.7206071313E-05 + -3.8106888040E-04 6.0165339124E-04 -2.6985702780E-05 + -2.0530227184E-04 9.2365341803E-06 -4.3293090322E-04 + 2.1385771526E-04 1.8162052836E-04 4.1571979862E-04 + -3.7544539666E-04 -4.0202233347E-05 -2.6685298191E-04 +:F: + -3.4776730913E-03 3.8275690718E-03 1.1949443759E-03 + -1.7480824538E-03 -1.7003214477E-03 1.2385384967E-03 + 1.1723043859E-02 -1.7646864976E-03 -2.1538743669E-03 + 1.1314247150E-02 -1.3047440100E-03 -6.8006411092E-04 + 1.1977966207E-02 1.0415081083E-03 9.8199214723E-04 + 1.4332571061E-02 3.0738773510E-03 3.8348778639E-04 + 1.0981200735E-02 -2.7635152335E-03 1.3703158178E-04 + 1.3547208867E-02 7.1575290306E-04 8.1326223398E-05 + 1.4005878124E-02 -1.0283982378E-03 -5.9158310152E-04 + -5.7162588360E-04 1.9564925314E-03 -2.3823970057E-03 + 5.4835383859E-03 -1.7015325656E-03 -1.0476491879E-03 + -1.1673692437E-02 -2.6129546216E-03 3.0228838381E-03 + -1.1410902684E-02 1.0200527365E-03 1.6671911124E-03 + -1.1692459092E-02 -8.4859735580E-04 -1.1073516414E-04 + -1.4306670408E-02 2.8899926425E-03 -2.1342714580E-03 + -1.1384916979E-02 -2.6811427830E-03 8.6163706811E-04 + -1.3407778278E-02 2.0398763266E-03 6.4893640370E-04 + -1.4198848041E-02 -2.3538523366E-04 -1.2849490041E-03 + 3.1659498444E-03 -2.6519021670E-04 1.3875651747E-02 + -2.6589548864E-03 3.4134653180E-04 -1.3708097381E-02 +:ANGLES: + 90.001 89.999 90.000 +:VOLUME: 6.7419329313E+03 +:LATVEC_SCALE: + 1.8891966347E+01 1.8891268202E+01 1.8890617343E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.0023004477E-05 9.9999999995E-01 0.0000000000E+00 + 1.7761975008E-05 -3.8700388792E-06 9.9999999983E-01 +:STRIO: + 7.1794771358E-01 -9.0707343760E-02 1.4397151280E-01 + -9.0707343760E-02 7.3522923383E-01 -2.7472493646E-02 + 1.4397151280E-01 -2.7472493646E-02 4.8060472523E-01 +:STRESS: + 4.9052916058E+00 -8.6875473693E-03 2.2003584782E-03 + -8.6875473693E-03 5.5252720398E+00 7.6876571030E-03 + 2.2003584782E-03 7.6876571030E-03 5.8213611868E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1873438922E+00 -8.2019796391E-02 1.4177115432E-01 + -8.2019796391E-02 -4.7900428059E+00 -3.5160150749E-02 + 1.4177115432E-01 -3.5160150749E-02 -5.3407564616E+00 +:PRESIO: 6.4459389088E-01 +:PRES: -5.4173082775E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7727143866E+00 +:PRESIG: 6.7851988514E-01 +:MIND: +Al - Al: 6.0802365623E+00 +C - C: 6.1827679284E+00 +Al - C: 6.2152823636E+00 + + +:MDSTEP: 7 +:MDTM: 20.12 +:TWIST: 0 +:TEL: 2400 +:TIO: 2477.96008257823 +:TEN: -2.6049476647E+00 +:KEN: 1.1182306517E-02 +:KENIG: 1.1770848965E-02 +:FEN: -2.6161299712E+00 +:UEN: -2.6090123541E+00 +:TSEN: -7.1176170294E-03 +:NPH_HAMIL: 1.6336004887E-04 +:NPH_ENTHALPY: -5.2074537358E+01 +:R: + 1.8886101024E+01 1.7144719657E-01 1.0937002437E-01 + 7.5035116307E-03 1.8849415350E+01 6.4244236505E+00 + 1.6856100732E-01 1.8775767654E+01 1.2515083556E+01 + 1.8817446563E+01 6.2619591229E+00 1.8776488482E+01 + 8.0138550342E-02 6.3968860186E+00 6.2877484139E+00 + 1.8857226263E+01 6.3886329286E+00 1.2577203251E+01 + 1.8701472515E+01 1.2444942385E+01 6.6037917693E-02 + 1.9986266484E-02 1.2625308068E+01 6.3934364000E+00 + 1.2276885324E-01 1.2474641424E+01 1.2628226479E+01 + 6.1872364878E+00 1.8882496982E+01 1.8734210832E+01 + 6.3045784698E+00 4.3351096794E-03 6.2192269379E+00 + 6.3123302144E+00 1.8770336254E+01 1.2700534842E+01 + 6.4239455898E+00 6.2848117549E+00 9.4821731567E-02 + 6.4827021596E+00 6.3824865727E+00 6.2832528232E+00 + 6.1141025955E+00 6.4385666413E+00 1.2517429224E+01 + 6.3031641397E+00 1.2384106744E+01 1.8873521985E+01 + 6.2075801376E+00 1.2741089788E+01 6.2891219569E+00 + 6.2516376858E+00 1.2594857963E+01 1.2484996135E+01 + 1.2644255102E+01 4.5199359446E-02 9.0775478910E-02 + 1.2501690776E+01 1.8878664430E+01 6.2420111218E+00 +:V: + -2.3787170898E-05 6.9945100151E-04 4.4383039749E-04 + 2.5593884409E-05 -1.6251905652E-04 5.2057220550E-04 + 7.0932785396E-04 -4.5957690821E-04 -3.1457843778E-04 + -2.6447860292E-04 -1.4085779030E-04 -4.5104457308E-04 + 3.5344249886E-04 4.0800118111E-04 -3.1259668990E-05 + -9.6874189443E-05 3.7908852460E-04 -5.8755113656E-05 + -7.3075391076E-04 -6.0104716579E-04 2.6677349841E-04 + 1.1437011776E-04 1.3379519266E-04 3.9327837249E-04 + 5.2965227288E-04 -4.7753443058E-04 1.4509859569E-04 + -4.4166442303E-04 -2.1312864804E-05 -6.2499008441E-04 + 4.4248317321E-05 1.4133483533E-05 -3.1194929240E-04 + 3.3726053481E-05 -4.8324455127E-04 4.4423369689E-04 + 4.8466208784E-04 -4.4299247345E-05 3.8600105207E-04 + 7.2049173686E-04 3.4604114547E-04 -5.1627867755E-05 + -7.7268956504E-04 5.8012837246E-04 -3.0504137720E-04 + -4.0065815711E-06 -8.4589900490E-04 -5.6428148174E-05 + -3.9244659079E-04 6.0358369557E-04 -2.6381930303E-05 + -2.1733124923E-04 9.0285171997E-06 -4.3416870513E-04 + 2.2042957270E-04 1.8110429436E-04 4.4247731336E-04 + -3.8100811706E-04 -3.9491302924E-05 -2.9323222673E-04 +:F: + -3.5506776866E-03 4.5700951245E-03 1.3729806003E-03 + -1.4457711665E-03 -2.0214159932E-03 1.5256024693E-03 + 1.1694304706E-02 -2.1398300655E-03 -2.5560159650E-03 + 1.1039508275E-02 -1.4833367929E-03 -8.3064543575E-04 + 1.1885655361E-02 1.2771310379E-03 1.1960562784E-03 + 1.4538772236E-02 3.6710386403E-03 4.6910512211E-04 + 1.0675863085E-02 -3.3875728854E-03 1.3610024867E-04 + 1.3752211759E-02 8.0719777536E-04 1.2160238207E-04 + 1.4122073021E-02 -1.2177097636E-03 -7.2118896893E-04 + -1.2833421009E-03 2.3511530430E-03 -2.8894194846E-03 + 5.9443971692E-03 -2.0252381588E-03 -1.1818960396E-03 + -1.1655703742E-02 -3.1253145938E-03 3.5656372756E-03 + -1.1173393141E-02 1.2579029176E-03 1.9726517065E-03 + -1.1533246719E-02 -9.7247782726E-04 -1.3061418671E-04 + -1.4497140525E-02 3.4654988071E-03 -2.5400120255E-03 + -1.1165680848E-02 -3.2536812801E-03 1.0116766285E-03 + -1.3561788454E-02 2.3750795256E-03 7.8772983892E-04 + -1.4367011861E-02 -2.6027913167E-04 -1.5187864699E-03 + 3.7693939579E-03 -3.0691513173E-04 1.4403734712E-02 + -3.1884233275E-03 4.1867475265E-04 -1.4194298686E-02 +:ANGLES: + 90.001 89.999 90.000 +:VOLUME: 6.7393762531E+03 +:LATVEC_SCALE: + 1.8889855201E+01 1.8888872668E+01 1.8887959186E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.4108071370E-05 9.9999999990E-01 0.0000000000E+00 + 2.4918786369E-05 -5.4912688321E-06 9.9999999967E-01 +:STRIO: + 7.2423082915E-01 -9.4068871154E-02 1.4629425110E-01 + -9.4068871154E-02 7.4114376019E-01 -2.7285001452E-02 + 1.4629425110E-01 -2.7285001452E-02 4.8729760580E-01 +:STRESS: + 4.8914684934E+00 -1.0613365212E-02 7.2963017252E-04 + -1.0613365212E-02 5.5179904003E+00 1.0466566658E-02 + 7.2963017252E-04 1.0466566658E-02 5.8252949771E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1672376643E+00 -8.3455505942E-02 1.4556462093E-01 + -8.3455505942E-02 -4.7768466402E+00 -3.7751568110E-02 + 1.4556462093E-01 -3.7751568110E-02 -5.3379973713E+00 +:PRESIO: 6.5089073172E-01 +:PRES: -5.4115846236E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7606938919E+00 +:PRESIG: 6.8514813865E-01 +:MIND: +Al - Al: 6.0360147805E+00 +C - C: 6.1532406529E+00 +Al - C: 6.1971716367E+00 + + +:MDSTEP: 8 +:MDTM: 22.30 +:TWIST: 0 +:TEL: 2400 +:TIO: 2505.12184314097 +:TEN: -2.6049670241E+00 +:KEN: 1.1304879570E-02 +:KENIG: 1.1899873231E-02 +:FEN: -2.6162719037E+00 +:UEN: -2.6091806470E+00 +:TSEN: -7.0912566200E-03 +:NPH_HAMIL: 2.6270657000E-04 +:NPH_ENTHALPY: -5.2074438012E+01 +:R: + 1.8882597585E+01 2.0041297466E-01 1.2772146007E-01 + 8.4990363526E-03 1.8839862475E+01 6.4449127954E+00 + 1.9807803860E-01 1.8753932854E+01 1.2499981007E+01 + 1.8804383982E+01 6.2551484140E+00 1.8754746913E+01 + 9.4966568070E-02 6.4128148294E+00 6.2854445371E+00 + 1.8851094641E+01 6.4033971872E+00 1.2572717404E+01 + 1.8668957921E+01 1.2418198598E+01 7.7056409191E-02 + 2.4943398424E-02 1.2628973045E+01 6.4086446060E+00 + 1.4493835900E-01 1.2453011913E+01 1.2632137784E+01 + 6.1682187766E+00 1.8878828088E+01 1.8705250476E+01 + 6.3057422595E+00 4.8714097867E-03 6.2052908155E+00 + 6.3127169910E+00 1.8747506408E+01 1.2716873367E+01 + 6.4429199287E+00 6.2820728774E+00 1.1079562166E-01 + 6.5114622305E+00 6.3958173091E+00 6.2800847272E+00 + 6.0811890911E+00 6.4616301158E+00 1.2502720780E+01 + 6.3020834525E+00 1.2347216659E+01 1.8868107791E+01 + 6.1903058150E+00 1.2764183948E+01 6.2870123805E+00 + 6.2416350268E+00 1.2593339839E+01 1.2464973332E+01 + 1.2651868513E+01 5.2666477758E-02 1.0961227600E-01 + 1.2484151204E+01 1.8874244491E+01 6.2283115365E+00 +:V: + -2.6810041603E-05 7.0369832634E-04 4.4513336741E-04 + 2.4510719401E-05 -1.6437327312E-04 5.2205393457E-04 + 7.1923342145E-04 -4.6159972049E-04 -3.1694821303E-04 + -2.5535303519E-04 -1.4219479386E-04 -4.5187645707E-04 + 3.6344267041E-04 4.0923176371E-04 -3.0172809846E-05 + -8.4581176904E-05 3.8247376959E-04 -5.8332251630E-05 + -7.2200038987E-04 -6.0424882844E-04 2.6693514292E-04 + 1.2603091041E-04 1.3453203858E-04 3.9346187589E-04 + 5.4163463696E-04 -4.7870068790E-04 1.4445489972E-04 + -4.4309127246E-04 -1.9175164131E-05 -6.2772013720E-04 + 4.9446482597E-05 1.2300942471E-05 -3.1304944956E-04 + 2.3940959199E-05 -4.8615526529E-04 4.4751767928E-04 + 4.7543350475E-04 -4.3149592795E-05 3.8784454763E-04 + 7.1095594106E-04 3.4522578290E-04 -5.1762301203E-05 + -7.8505117681E-04 5.8336135761E-04 -3.0738480996E-04 + -1.3302633214E-05 -8.4899631160E-04 -5.5525411900E-05 + -4.0395868305E-04 6.0580412526E-04 -2.5663397738E-05 + -2.2950286964E-04 8.8046477557E-06 -4.3560950955E-04 + 2.2813289518E-04 1.8051740076E-04 4.7028890763E-04 + -3.8757796741E-04 -3.8632644479E-05 -3.2058123974E-04 +:F: + -3.6341831436E-03 5.2895560182E-03 1.5499040255E-03 + -1.1392786788E-03 -2.3333454686E-03 1.7976254887E-03 + 1.1653975486E-02 -2.5194200663E-03 -2.9428857535E-03 + 1.0754586846E-02 -1.6451992272E-03 -9.7690206040E-04 + 1.1797954551E-02 1.5030738007E-03 1.4073485411E-03 + 1.4739639730E-02 4.2509826992E-03 5.5636523855E-04 + 1.0377471706E-02 -4.0102107248E-03 1.3248780355E-04 + 1.3956540805E-02 8.9749218714E-04 1.6310027933E-04 + 1.4223134093E-02 -1.3952053532E-03 -8.5407952387E-04 + -1.9747458165E-03 2.7475560740E-03 -3.3705749038E-03 + 6.4097621882E-03 -2.3403638761E-03 -1.3128649010E-03 + -1.1636118783E-02 -3.6303137278E-03 4.0769803843E-03 + -1.0934013500E-02 1.4875254813E-03 2.2724486827E-03 + -1.1378161275E-02 -1.0974383587E-03 -1.5632995024E-04 + -1.4675117258E-02 4.0313840931E-03 -2.9346757675E-03 + -1.0950876126E-02 -3.8178567470E-03 1.1619556821E-03 + -1.3707020938E-02 2.7000561918E-03 9.2136721456E-04 + -1.4525239885E-02 -2.7298448526E-04 -1.7440899865E-03 + 4.3591957569E-03 -3.4419877136E-04 1.4977020713E-02 + -3.7175057591E-03 4.9891026086E-04 -1.4724201206E-02 +:ANGLES: + 90.001 89.998 90.000 +:VOLUME: 6.7363960288E+03 +:LATVEC_SCALE: + 1.8887396112E+01 1.8886079398E+01 1.8884857485E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.8916083408E-05 9.9999999982E-01 0.0000000000E+00 + 3.3336672494E-05 -7.4393224114E-06 9.9999999942E-01 +:STRIO: + 7.3182302774E-01 -9.7585489782E-02 1.4903369321E-01 + -9.7585489782E-02 7.4816384589E-01 -2.7156560618E-02 + 1.4903369321E-01 -2.7156560618E-02 4.9496256722E-01 +:STRESS: + 4.8764620163E+00 -1.2606943860E-02 -1.4958760944E-03 + -1.2606943860E-02 5.5087180255E+00 1.3560902135E-02 + -1.4958760944E-03 1.3560902135E-02 5.8292182257E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1446389886E+00 -8.4978545921E-02 1.5052956930E-01 + -8.4978545921E-02 -4.7605541796E+00 -4.0717462753E-02 + 1.5052956930E-01 -4.0717462753E-02 -5.3342556585E+00 +:PRESIO: 6.5831648028E-01 +:PRES: -5.4047994225E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7464829422E+00 +:PRESIG: 6.9296471609E-01 +:MIND: +Al - Al: 5.9915595227E+00 +C - C: 6.1214777156E+00 +Al - C: 6.1784749440E+00 + + +:MDSTEP: 9 +:MDTM: 24.93 +:TWIST: 0 +:TEL: 2400 +:TIO: 2536.43312437492 +:TEN: -2.6049876277E+00 +:KEN: 1.1446178191E-02 +:KENIG: 1.2048608622E-02 +:FEN: -2.6164338059E+00 +:UEN: -2.6093727686E+00 +:TSEN: -7.0610373212E-03 +:NPH_HAMIL: 4.0449050420E-04 +:NPH_ENTHALPY: -5.2074296228E+01 +:R: + 1.8878621640E+01 2.2955761619E-01 1.4612337599E-01 + 9.4495857353E-03 1.8829830570E+01 6.4653124601E+00 + 2.2799826687E-01 1.8731612706E+01 1.2484482585E+01 + 1.8791370082E+01 6.2481426436E+00 1.8732531330E+01 + 1.1020584533E-01 6.4286586450E+00 6.2830418340E+00 + 1.8845141043E+01 6.4181698421E+00 1.2567955644E+01 + 1.8636453261E+01 1.2391054926E+01 8.8077638125E-02 + 3.0384071544E-02 1.2632401505E+01 6.4237075115E+00 + 1.6760643340E-01 1.2431068372E+01 1.2635722294E+01 + 6.1490299046E+00 1.8874851443E+01 1.8675734350E+01 + 6.3070210249E+00 5.3241372451E-03 6.1911635933E+00 + 6.3125867586E+00 1.8724152487E+01 1.2733054306E+01 + 6.4613915405E+00 6.2792537642E+00 1.2684531282E-01 + 6.5397103977E+00 6.4089731869E+00 6.2767634956E+00 + 6.0476660624E+00 6.4846928707E+00 1.2487617275E+01 + 6.3005223953E+00 1.2309928631E+01 1.8862290702E+01 + 6.1724406832E+00 1.2787100947E+01 6.2847873313E+00 + 6.2310202057E+00 1.2591543265E+01 1.2444597606E+01 + 1.2659590213E+01 6.0105428509E-02 1.2961488325E-01 + 1.2466086927E+01 1.8869464773E+01 6.2133169022E+00 +:V: + -2.9909450902E-05 7.0855408314E-04 4.4659483311E-04 + 2.3687094798E-05 -1.6648943961E-04 5.2376990996E-04 + 7.2911487588E-04 -4.6395254169E-04 -3.1964490879E-04 + -2.4647466476E-04 -1.4366343040E-04 -4.5283978109E-04 + 3.7337866812E-04 4.1065721142E-04 -2.8910615623E-05 + -7.2122344918E-05 3.8634742575E-04 -5.7836507496E-05 + -7.1350568094E-04 -6.0798564665E-04 2.6709940692E-04 + 1.3786688643E-04 1.3534711703E-04 3.9368987989E-04 + 5.5370615625E-04 -4.8002128782E-04 1.4370066055E-04 + -4.4509819661E-04 -1.6703551285E-05 -6.3085572895E-04 + 5.5038876200E-05 1.0207945579E-05 -3.1426646099E-04 + 1.4171825657E-05 -4.8949761163E-04 4.5122740290E-04 + 4.6641418369E-04 -4.1813426053E-05 3.8994551732E-04 + 7.0156042443E-04 3.4431219829E-04 -5.1922053639E-05 + -7.9757169200E-04 5.8707754126E-04 -3.1006123391E-04 + -2.2422351082E-05 -8.5258006548E-04 -5.4497858595E-05 + -4.1559807505E-04 6.0830577896E-04 -2.4833840034E-05 + -2.4180838361E-04 8.5753168597E-06 -4.3724639430E-04 + 2.3694191033E-04 1.7986787196E-04 4.9924293323E-04 + -3.9515187481E-04 -3.7620324177E-05 -3.4898608398E-04 +:F: + -3.7306100830E-03 5.9809616281E-03 1.7238515832E-03 + -8.2896869379E-04 -2.6357617503E-03 2.0532860112E-03 + 1.1602228872E-02 -2.9025190777E-03 -3.3122482133E-03 + 1.0459489902E-02 -1.7885636129E-03 -1.1182008351E-03 + 1.1713776570E-02 1.7190549537E-03 1.6154437239E-03 + 1.4932917307E-02 4.8126607631E-03 6.4526000214E-04 + 1.0088720202E-02 -4.6282251614E-03 1.2579090307E-04 + 1.4159645776E-02 9.8595471451E-04 2.0590744445E-04 + 1.4306560744E-02 -1.5616276375E-03 -9.8965978948E-04 + -2.6436591216E-03 3.1465617615E-03 -3.8194125475E-03 + 6.8784847074E-03 -2.6450013191E-03 -1.4416647639E-03 + -1.1615529869E-02 -4.1267626899E-03 4.5524277617E-03 + -1.0693213024E-02 1.7026625673E-03 2.5640673487E-03 + -1.1227381718E-02 -1.2242727508E-03 -1.8618063415E-04 + -1.4836818245E-02 4.5862577027E-03 -3.3172982397E-03 + -1.0742473799E-02 -4.3672584109E-03 1.3118630395E-03 + -1.3843202714E-02 3.0138724681E-03 1.0509915693E-03 + -1.4671516489E-02 -2.7307497482E-04 -1.9613012301E-03 + 4.9349047855E-03 -3.7740050484E-04 1.5597139922E-02 + -4.2433551096E-03 5.8248133105E-04 -1.5300063056E-02 +:ANGLES: + 90.001 89.998 90.001 +:VOLUME: 6.7329934984E+03 +:LATVEC_SCALE: + 1.8884590638E+01 1.8882889368E+01 1.8881312140E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -2.4461733651E-05 9.9999999970E-01 0.0000000000E+00 + 4.3061213862E-05 -9.7404559204E-06 9.9999999903E-01 +:STRIO: + 7.4072172303E-01 -1.0126293350E-01 1.5220717392E-01 + -1.0126293350E-01 7.5628807872E-01 -2.7089536100E-02 + 1.5220717392E-01 -2.7089536100E-02 5.0363486429E-01 +:STRESS: + 4.8601580145E+00 -1.4666898120E-02 -4.4903321650E-03 + -1.4666898120E-02 5.4973230897E+00 1.6996456550E-02 + -4.4903321650E-03 1.6996456550E-02 5.8330492725E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1194362915E+00 -8.6596035379E-02 1.5669750608E-01 + -8.6596035379E-02 -4.7410350110E+00 -4.4085992650E-02 + 1.5669750608E-01 -4.4085992650E-02 -5.3294144082E+00 +:PRESIO: 6.6688155535E-01 +:PRES: -5.3968434589E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7299619035E+00 +:PRESIG: 7.0198058458E-01 +:MIND: +Al - Al: 5.9468400950E+00 +C - C: 6.0874065260E+00 +Al - C: 6.1591349433E+00 + + +:MDSTEP: 10 +:MDTM: 21.66 +:TWIST: 0 +:TEL: 2400 +:TIO: 2571.92159550967 +:TEN: -2.6050111329E+00 +:KEN: 1.1606327245E-02 +:KENIG: 1.2217186573E-02 +:FEN: -2.6166174601E+00 +:UEN: -2.6095905070E+00 +:TSEN: -7.0269531415E-03 +:NPH_HAMIL: 5.5464680280E-04 +:NPH_ENTHALPY: -5.2074146072E+01 +:R: + 1.8874171606E+01 2.5890451788E-01 1.6458139221E-01 + 1.0366066914E-02 1.8819310253E+01 6.4856309876E+00 + 2.5831975181E-01 1.8708795151E+01 1.2468575672E+01 + 1.8778397406E+01 6.2409368060E+00 1.8709837204E+01 + 1.2585339533E-01 6.4444248455E+00 6.2805475196E+00 + 1.8839374519E+01 6.4329701037E+00 1.2562921073E+01 + 1.8603950628E+01 1.2363491181E+01 9.9101138368E-02 + 3.6315426279E-02 1.2635597004E+01 6.4386261875E+00 + 1.9077611261E-01 1.2408805861E+01 1.2638975069E+01 + 6.1296482066E+00 1.8870581566E+01 1.8645647431E+01 + 6.3084318874E+00 5.6825316974E-03 6.1768410753E+00 + 6.3119413136E+00 1.8700258461E+01 1.2749093681E+01 + 6.4793690017E+00 6.2763623169E+00 1.4298053147E-01 + 6.5674522037E+00 6.4219497426E+00 6.2732880883E+00 + 6.0135295793E+00 6.5077736942E+00 1.2472105731E+01 + 6.2984897149E+00 1.2272224534E+01 1.8856075896E+01 + 6.1539810171E+00 1.2809851765E+01 6.2824513469E+00 + 6.2197893545E+00 1.2589468663E+01 1.2423861808E+01 + 1.2667466171E+01 6.7513456134E-02 1.5083115792E-01 + 1.2447458361E+01 1.8864332836E+01 6.1969826551E+00 +:V: + -3.3096521145E-05 7.1399342040E-04 4.4821152379E-04 + 2.3125873142E-05 -1.6885978187E-04 5.2570595357E-04 + 7.3896352774E-04 -4.6663776712E-04 -3.2265307447E-04 + -2.3785125361E-04 -1.4524759462E-04 -4.5393041362E-04 + 3.8325352231E-04 4.1226922294E-04 -2.7475812957E-05 + -5.9503814472E-05 3.9069335179E-04 -5.7266465725E-05 + -7.0526128916E-04 -6.1225299076E-04 2.6726367255E-04 + 1.4987712720E-04 1.3623906959E-04 3.9396382962E-04 + 5.6585199819E-04 -4.8148666667E-04 1.4283323670E-04 + -4.4766637006E-04 -1.3895851214E-05 -6.3436676960E-04 + 6.1029089706E-05 7.8639983788E-06 -3.1559883784E-04 + 4.4183965940E-06 -4.9326368874E-04 4.5533031275E-04 + 4.5760447604E-04 -4.0305216621E-05 3.9229610591E-04 + 6.9230092452E-04 3.4329860028E-04 -5.2109929753E-05 + -8.1023718021E-04 5.9126727200E-04 -3.1306020382E-04 + -3.1371210556E-05 -8.5663530977E-04 -5.3345546706E-05 + -4.2735730854E-04 6.1107870551E-04 -2.3896302899E-05 + -2.5423798392E-04 8.3505794340E-06 -4.3907289748E-04 + 2.4682926809E-04 1.7916259317E-04 5.2943253064E-04 + -4.0372250876E-04 -3.6447198936E-05 -3.7853804636E-04 +:F: + -3.8402868113E-03 6.6406660987E-03 1.8926530110E-03 + -5.1568071171E-04 -2.9289000763E-03 2.2912792519E-03 + 1.1540516459E-02 -3.2875595785E-03 -3.6616988393E-03 + 1.0155364440E-02 -1.9119447138E-03 -1.2544124732E-03 + 1.1632515469E-02 1.9250291125E-03 1.8201085828E-03 + 1.5118061197E-02 5.3536218271E-03 7.3583786470E-04 + 9.8097483140E-03 -5.2393346710E-03 1.1592412661E-04 + 1.4360721707E-02 1.0728717756E-03 2.5086777062E-04 + 1.4371356599E-02 -1.7162992102E-03 -1.1285178750E-03 + -3.2899808931E-03 3.5477874351E-03 -4.2285094859E-03 + 7.3517786422E-03 -2.9372228105E-03 -1.5688342194E-03 + -1.1595705028E-02 -4.6124815754E-03 4.9856753467E-03 + -1.0452191519E-02 1.8976562415E-03 2.8448191882E-03 + -1.1081527873E-02 -1.3533164820E-03 -2.1852206261E-04 + -1.4980660785E-02 5.1287633559E-03 -3.6868893424E-03 + -1.0539967239E-02 -4.8953694307E-03 1.4618475740E-03 + -1.3969712012E-02 3.3149438293E-03 1.1770604386E-03 + -1.4805337600E-02 -2.6177715165E-04 -2.1710550044E-03 + 5.4952438387E-03 -4.0736600893E-04 1.6267438467E-02 + -4.7642561946E-03 6.7023203323E-04 -1.5925072320E-02 +:ANGLES: + 90.002 89.997 90.001 +:VOLUME: 6.7291701038E+03 +:LATVEC_SCALE: + 1.8881440513E+01 1.8879303768E+01 1.8877323078E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -3.0760789118E-05 9.9999999953E-01 0.0000000000E+00 + 5.4148877411E-05 -1.2424560584E-05 9.9999999846E-01 +:STRIO: + 7.5092369007E-01 -1.0510794609E-01 1.5583335485E-01 + -1.0510794609E-01 7.6551244415E-01 -2.7087015341E-02 + 1.5583335485E-01 -2.7087015341E-02 5.1335316093E-01 +:STRESS: + 4.8426560981E+00 -1.6770773452E-02 -8.2783909606E-03 + -1.6770773452E-02 5.4837002809E+00 2.0750872322E-02 + -8.2783909606E-03 2.0750872322E-02 5.8368465094E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.0917324081E+00 -8.8337172636E-02 1.6411174581E-01 + -8.8337172636E-02 -4.7181878368E+00 -4.7837887663E-02 + 1.6411174581E-01 -4.7837887663E-02 -5.3234933485E+00 +:PRESIO: 6.7659643172E-01 +:PRES: -5.3877342962E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7111378644E+00 +:PRESIG: 7.1220677023E-01 +:MIND: +Al - Al: 5.9018291118E+00 +C - C: 6.0509496155E+00 +Al - C: 6.1390950306E+00 diff --git a/tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.refout b/tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.refout new file mode 100644 index 00000000..28409f5e --- /dev/null +++ b/tests/Al18C2_NPH_full_flex/standard/Al18C2_NPH_full_flex.refout @@ -0,0 +1,647 @@ +*************************************************************************** +* SPARC (version December 03, 2025) * +* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * +* Distributed under GNU General Public License 3 (GPL) * +* Start time: Sun Apr 5 14:08:59 2026 * +*************************************************************************** + Input parameters +*************************************************************************** +LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 +LATVEC: +1.000000000000000 0.000000000000000 0.000000000000000 +0.000000000000000 1.000000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 +WARNING: This system is cuboidal. To get the best performance, please align the lattice vectors onto standard cartesian coordinate. +FD_GRID: 76 76 76 +FD_ORDER: 12 +BC: P P P +KPOINT_GRID: 1 1 1 +KPOINT_SHIFT: 0 0 0 +SPIN_TYP: 0 +ELEC_TEMP_TYPE: Fermi-Dirac +ELEC_TEMP: 2400 +EXCHANGE_CORRELATION: GGA_PBE +HUBBARD_FLAG: 0 +NSTATES: 80 +CHEB_DEGREE: 30 +CHEFSI_BOUND_FLAG: 0 +CALC_STRESS: 1 +TWTIME: 1E+09 +MD_FLAG: 1 +MD_METHOD: NPH +MD_TIMESTEP: 1 +MD_NSTEP: 10 +ION_VEL_DSTR: 2 +ION_VEL_DSTR_RAND: 0 +ION_TEMP: 2400 +NPH_SCALE_VECS: 1 2 3 +NPH_SCALE_CONSTRAINTS: none +NPH_ANGLES: 1 +NPH_BMASS: 0.5 +TARGET_STRESS: 0.1 0.1 0.1 0 0 0 GPa +MAXIT_SCF: 100 +MINIT_SCF: 2 +MAXIT_POISSON: 3000 +TOL_SCF: 1.00E-06 +POISSON_SOLVER: AAR +TOL_POISSON: 1.00E-08 +TOL_LANCZOS: 1.00E-02 +TOL_PSEUDOCHARGE: 1.00E-09 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +TOL_PRECOND: 6.18E-05 +PRECOND_KERKER_KTF: 1 +PRECOND_KERKER_THRESH: 0 +MIXING_PARAMETER: 1 +MIXING_HISTORY: 7 +PULAY_FREQUENCY: 1 +PULAY_RESTART: 0 +REFERENCE_CUTOFF: 0.5 +RHO_TRIGGER: 4 +NUM_CHEFSI: 1 +FIX_RAND: 0 +VERBOSITY: 1 +PRINT_FORCES: 1 +PRINT_ATOMS: 1 +PRINT_EIGEN: 0 +PRINT_DENSITY: 0 +PRINT_MDOUT: 1 +PRINT_VELS: 1 +PRINT_RESTART: 1 +PRINT_RESTART_FQ: 1 +PRINT_ENERGY_DENSITY: 0 +OUTPUT_FILE: Al18C2_NPH_full_flex +*************************************************************************** + Cell +*************************************************************************** +Lattice vectors (Bohr): +18.897259886000001 0.000000000000000 0.000000000000000 +0.000000000000000 18.897259886000001 0.000000000000000 +0.000000000000000 0.000000000000000 18.897259886000001 +Volume: 6.7483330373E+03 (Bohr^3) +Density: 7.5528236408E-02 (amu/Bohr^3), 8.4635982984E-01 (g/cc) +*************************************************************************** + Parallelization +*************************************************************************** +NP_SPIN_PARAL: 1 +NP_KPOINT_PARAL: 1 +NP_BAND_PARAL: 20 +NP_DOMAIN_PARAL: 1 1 3 +NP_DOMAIN_PHI_PARAL: 3 4 5 +EIG_SERIAL_MAXNS: 1500 +*************************************************************************** + Initialization +*************************************************************************** +Number of processors : 60 +Mesh spacing : 0.248648 (Bohr) +Number of symmetry adapted k-points: 1 +Output printed to : Al18C2_NPH_full_flex.out_01 +MD output printed to : Al18C2_NPH_full_flex.aimd_01 +Total number of atom types : 2 +Total number of atoms : 20 +Total number of electrons : 62 +Atom type 1 (valence electrons) : Al 3 +Pseudopotential : ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +Atomic mass : 26.9815385 +Pseudocharge radii of atom type 1 : 6.96 6.96 6.96 (x, y, z dir) +Number of atoms of type 1 : 18 +Atom type 2 (valence electrons) : C 4 +Pseudopotential : ../../../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 +Atomic mass : 12.011 +Pseudocharge radii of atom type 2 : 7.21 7.21 7.21 (x, y, z dir) +Number of atoms of type 2 : 2 +Estimated total memory usage : 1.97 GB +Estimated memory per processor : 33.66 MB +=================================================================== + Self Consistent Field (SCF#1) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6092742152E+00 2.178E-01 5.973 +2 -2.6449156352E+00 6.062E-01 1.750 +3 -2.6194694253E+00 3.465E-01 1.721 +4 -2.6168894089E+00 2.156E-01 1.707 +5 -2.6184911807E+00 2.751E-01 1.709 +6 -2.6160423945E+00 1.218E-01 1.690 +7 -2.6160188750E+00 1.180E-01 1.704 +8 -2.6159489523E+00 9.331E-02 1.694 +9 -2.6157124703E+00 9.906E-03 1.674 +10 -2.6157153826E+00 1.328E-02 1.671 +11 -2.6157117979E+00 4.535E-03 1.673 +12 -2.6157118968E+00 6.063E-04 1.659 +13 -2.6157121858E+00 6.727E-04 1.654 +14 -2.6157123363E+00 2.813E-04 1.628 +15 -2.6157123674E+00 1.850E-04 1.631 +16 -2.6157123857E+00 6.798E-05 1.611 +17 -2.6157123849E+00 2.346E-05 1.597 +18 -2.6157123852E+00 2.214E-05 1.576 +19 -2.6157123874E+00 3.810E-05 1.575 +20 -2.6157123872E+00 6.476E-06 1.577 +21 -2.6157123862E+00 2.400E-06 1.556 +22 -2.6157123870E+00 1.274E-06 1.531 +23 -2.6157123874E+00 6.671E-07 1.533 +Total number of SCF: 23 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157123874E+00 (Ha/atom) +Total free energy : -5.2314247747E+01 (Ha) +Band structure energy : -9.0952979915E+00 (Ha) +Exchange correlation energy : -2.0462262749E+01 (Ha) +Self and correction energy : -7.6945217010E+01 (Ha) +-Entropy*kb*T : -1.4401402531E-01 (Ha) +Fermi level : -2.8332764046E-02 (Ha) +RMS force : 1.0671807882E-02 (Ha/Bohr) +Maximum force : 1.3274761023E-02 (Ha/Bohr) +Time for force calculation : 0.059 (sec) +Pressure : -5.4299705557E+00 (GPa) +Maximum stress : 5.8022455634E+00 (GPa) +Time for stress calculation : 0.152 (sec) +MD step time : 43.137 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8969060788077 18.8968605644746 18.8968172803017 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248644 (Bohr) +Mesh spacing in y-direction : 0.248643 (Bohr) +Mesh spacing in z direction : 0.248642 (Bohr) +=================================================================== + Self Consistent Field (SCF#2) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159453145E+00 3.771E-02 1.750 +2 -2.6165140776E+00 1.885E-01 1.733 +3 -2.6157887968E+00 5.290E-02 1.719 +4 -2.6159245108E+00 9.227E-02 1.724 +5 -2.6157320323E+00 3.545E-03 1.699 +6 -2.6157309384E+00 2.144E-03 1.697 +7 -2.6157309938E+00 9.750E-04 1.684 +8 -2.6157312715E+00 5.250E-04 1.679 +9 -2.6157314815E+00 3.426E-04 1.679 +10 -2.6157316213E+00 1.553E-04 1.656 +11 -2.6157316724E+00 7.449E-05 1.618 +12 -2.6157316790E+00 5.489E-05 1.607 +13 -2.6157316801E+00 8.768E-05 1.603 +14 -2.6157316805E+00 1.874E-05 1.606 +15 -2.6157316810E+00 5.925E-06 1.599 +16 -2.6157316815E+00 3.325E-06 1.580 +17 -2.6157316813E+00 2.073E-06 1.563 +18 -2.6157316839E+00 1.758E-06 1.555 +19 -2.6157316829E+00 8.137E-07 1.542 +Total number of SCF: 19 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157316829E+00 (Ha/atom) +Total free energy : -5.2314633659E+01 (Ha) +Band structure energy : -9.0959882644E+00 (Ha) +Exchange correlation energy : -2.0462742230E+01 (Ha) +Self and correction energy : -7.6945216544E+01 (Ha) +-Entropy*kb*T : -1.4390662324E-01 (Ha) +Fermi level : -2.8355567976E-02 (Ha) +RMS force : 1.0685595228E-02 (Ha/Bohr) +Maximum force : 1.3505718931E-02 (Ha/Bohr) +Time for force calculation : 0.058 (sec) +Pressure : -5.4296548882E+00 (GPa) +Maximum stress : 5.8059573203E+00 (GPa) +Time for stress calculation : 0.146 (sec) +MD step time : 31.924 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8961990092167 18.8960616739701 18.8959318921879 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248634 (Bohr) +Mesh spacing in y-direction : 0.248632 (Bohr) +Mesh spacing in z direction : 0.248631 (Bohr) +=================================================================== + Self Consistent Field (SCF#3) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159887795E+00 3.836E-02 1.749 +2 -2.6165801663E+00 1.901E-01 1.746 +3 -2.6158311971E+00 5.426E-02 1.724 +4 -2.6159688691E+00 9.340E-02 1.754 +5 -2.6157718321E+00 3.603E-03 1.921 +6 -2.6157706803E+00 2.224E-03 1.708 +7 -2.6157707171E+00 9.917E-04 1.697 +8 -2.6157710050E+00 5.342E-04 1.689 +9 -2.6157712259E+00 3.533E-04 1.705 +10 -2.6157713731E+00 1.590E-04 1.679 +11 -2.6157714271E+00 7.773E-05 1.656 +12 -2.6157714345E+00 5.855E-05 1.631 +13 -2.6157714354E+00 9.656E-05 1.612 +14 -2.6157714357E+00 1.846E-05 1.650 +15 -2.6157714363E+00 6.270E-06 1.605 +16 -2.6157714371E+00 3.702E-06 1.611 +17 -2.6157714367E+00 2.383E-06 1.588 +18 -2.6157714392E+00 1.772E-06 1.584 +19 -2.6157714388E+00 7.683E-07 1.554 +Total number of SCF: 19 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157714388E+00 (Ha/atom) +Total free energy : -5.2315428776E+01 (Ha) +Band structure energy : -9.0967767746E+00 (Ha) +Exchange correlation energy : -2.0463959202E+01 (Ha) +Self and correction energy : -7.6945216223E+01 (Ha) +-Entropy*kb*T : -1.4373359552E-01 (Ha) +Fermi level : -2.8386604332E-02 (Ha) +RMS force : 1.0744109791E-02 (Ha/Bohr) +Maximum force : 1.3772644110E-02 (Ha/Bohr) +Time for force calculation : 0.058 (sec) +Pressure : -5.4282059658E+00 (GPa) +Maximum stress : 5.8097442547E+00 (GPa) +Time for stress calculation : 0.147 (sec) +MD step time : 32.524 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.895139401909 18.894863173238 18.894603548499 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.24862 (Bohr) +Mesh spacing in y-direction : 0.248617 (Bohr) +Mesh spacing in z direction : 0.248613 (Bohr) +=================================================================== + Self Consistent Field (SCF#4) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6157721901E+00 3.396E-03 1.643 +2 -2.6158309711E+00 3.291E-03 1.707 +3 -2.6158339262E+00 1.173E-02 1.702 +4 -2.6158314840E+00 4.766E-03 1.682 +5 -2.6158310724E+00 1.756E-04 1.636 +6 -2.6158310721E+00 5.591E-05 1.626 +7 -2.6158310721E+00 3.817E-05 1.635 +8 -2.6158310738E+00 2.116E-05 1.633 +9 -2.6158310738E+00 1.081E-05 1.641 +10 -2.6158310740E+00 4.456E-06 1.615 +11 -2.6158310764E+00 1.732E-06 1.601 +12 -2.6158310739E+00 9.192E-07 1.572 +Total number of SCF: 12 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6158310739E+00 (Ha/atom) +Total free energy : -5.2316621478E+01 (Ha) +Band structure energy : -9.0976578501E+00 (Ha) +Exchange correlation energy : -2.0465911522E+01 (Ha) +Self and correction energy : -7.6945216371E+01 (Ha) +-Entropy*kb*T : -1.4349316520E-01 (Ha) +Fermi level : -2.8425144418E-02 (Ha) +RMS force : 1.0855688887E-02 (Ha/Bohr) +Maximum force : 1.4071676597E-02 (Ha/Bohr) +Time for force calculation : 0.058 (sec) +Pressure : -5.4256380365E+00 (GPa) +Maximum stress : 5.8135818946E+00 (GPa) +Time for stress calculation : 0.146 (sec) +MD step time : 20.316 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8937281578722 18.893265226623 18.8928320835727 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248602 (Bohr) +Mesh spacing in y-direction : 0.248596 (Bohr) +Mesh spacing in z direction : 0.24859 (Bohr) +=================================================================== + Self Consistent Field (SCF#5) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6158512013E+00 3.349E-03 1.650 +2 -2.6159093950E+00 1.597E-03 1.670 +3 -2.6159126147E+00 1.313E-02 1.672 +4 -2.6159096928E+00 2.783E-04 1.636 +5 -2.6159097131E+00 9.128E-04 1.635 +6 -2.6159096967E+00 1.164E-04 1.626 +7 -2.6159096927E+00 2.577E-05 1.610 +8 -2.6159096950E+00 1.312E-05 1.600 +9 -2.6159096953E+00 8.518E-06 1.604 +10 -2.6159096955E+00 4.586E-06 1.592 +11 -2.6159096949E+00 2.079E-06 1.576 +12 -2.6159096929E+00 1.056E-06 1.547 +13 -2.6159096953E+00 5.670E-07 1.544 +Total number of SCF: 13 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6159096953E+00 (Ha/atom) +Total free energy : -5.2318193906E+01 (Ha) +Band structure energy : -9.0985957149E+00 (Ha) +Exchange correlation energy : -2.0468602206E+01 (Ha) +Self and correction energy : -7.6945216772E+01 (Ha) +-Entropy*kb*T : -1.4318392656E-01 (Ha) +Fermi level : -2.8469954000E-02 (Ha) +RMS force : 1.1017305706E-02 (Ha/Bohr) +Maximum force : 1.4399103704E-02 (Ha/Bohr) +Time for force calculation : 0.058 (sec) +Pressure : -5.4219867854E+00 (GPa) +Maximum stress : 5.8174467263E+00 (GPa) +Time for stress calculation : 0.146 (sec) +MD step time : 21.557 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.891966347183 18.8912682020003 18.8906173432828 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248579 (Bohr) +Mesh spacing in y-direction : 0.248569 (Bohr) +Mesh spacing in z direction : 0.248561 (Bohr) +=================================================================== + Self Consistent Field (SCF#6) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159491908E+00 3.375E-03 1.633 +2 -2.6160086084E+00 1.638E-03 1.684 +3 -2.6160113629E+00 1.130E-02 1.695 +4 -2.6160090193E+00 2.369E-03 1.654 +5 -2.6160089114E+00 3.573E-04 1.637 +6 -2.6160089106E+00 6.556E-05 1.637 +7 -2.6160089096E+00 3.827E-05 1.635 +8 -2.6160089111E+00 2.354E-05 1.629 +9 -2.6160089113E+00 1.264E-05 1.631 +10 -2.6160089116E+00 5.536E-06 1.610 +11 -2.6160089134E+00 2.120E-06 1.588 +12 -2.6160089114E+00 1.233E-06 1.340 +13 -2.6160089132E+00 1.192E-06 1.542 +14 -2.6160089143E+00 7.975E-07 1.539 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6160089143E+00 (Ha/atom) +Total free energy : -5.2320178287E+01 (Ha) +Band structure energy : -9.0996156031E+00 (Ha) +Exchange correlation energy : -2.0472041483E+01 (Ha) +Self and correction energy : -7.6945217134E+01 (Ha) +-Entropy*kb*T : -1.4280434573E-01 (Ha) +Fermi level : -2.8520893094E-02 (Ha) +RMS force : 1.1215195500E-02 (Ha/Bohr) +Maximum force : 1.4750864053E-02 (Ha/Bohr) +Time for force calculation : 0.058 (sec) +Pressure : -5.4173082775E+00 (GPa) +Maximum stress : 5.8213611868E+00 (GPa) +Time for stress calculation : 0.146 (sec) +MD step time : 25.870 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8898552008476 18.8888726684425 18.8879591855561 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248551 (Bohr) +Mesh spacing in y-direction : 0.248538 (Bohr) +Mesh spacing in z direction : 0.248526 (Bohr) +=================================================================== + Self Consistent Field (SCF#7) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6160704294E+00 3.395E-03 1.640 +2 -2.6161297706E+00 2.678E-03 1.676 +3 -2.6161328479E+00 1.169E-02 1.689 +4 -2.6161302400E+00 3.858E-03 1.649 +5 -2.6161299710E+00 2.974E-04 1.624 +6 -2.6161299699E+00 5.459E-05 1.627 +7 -2.6161299701E+00 3.235E-05 1.620 +8 -2.6161299721E+00 1.760E-05 1.622 +9 -2.6161299717E+00 9.479E-06 1.608 +10 -2.6161299721E+00 4.355E-06 1.614 +11 -2.6161299733E+00 1.726E-06 1.589 +12 -2.6161299712E+00 8.758E-07 1.564 +Total number of SCF: 12 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6161299712E+00 (Ha/atom) +Total free energy : -5.2322599423E+01 (Ha) +Band structure energy : -9.1007596027E+00 (Ha) +Exchange correlation energy : -2.0476235781E+01 (Ha) +Self and correction energy : -7.6945216990E+01 (Ha) +-Entropy*kb*T : -1.4235234059E-01 (Ha) +Fermi level : -2.8578254889E-02 (Ha) +RMS force : 1.1438253828E-02 (Ha/Bohr) +Maximum force : 1.5120463831E-02 (Ha/Bohr) +Time for force calculation : 0.058 (sec) +Pressure : -5.4115846236E+00 (GPa) +Maximum stress : 5.8252949771E+00 (GPa) +Time for stress calculation : 0.147 (sec) +MD step time : 20.117 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8873961119305 18.8860793984257 18.8848574853724 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248518 (Bohr) +Mesh spacing in y-direction : 0.248501 (Bohr) +Mesh spacing in z direction : 0.248485 (Bohr) +=================================================================== + Self Consistent Field (SCF#8) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6162113444E+00 3.456E-03 1.654 +2 -2.6162724640E+00 7.193E-03 1.671 +3 -2.6162738573E+00 1.102E-02 1.691 +4 -2.6162725959E+00 5.510E-03 1.683 +5 -2.6162718968E+00 1.678E-04 1.647 +6 -2.6162719005E+00 5.760E-05 1.633 +7 -2.6162719010E+00 3.752E-05 1.640 +8 -2.6162719024E+00 2.045E-05 1.640 +9 -2.6162719023E+00 1.115E-05 1.627 +10 -2.6162719028E+00 5.535E-06 1.618 +11 -2.6162719043E+00 2.103E-06 1.595 +12 -2.6162719026E+00 1.228E-06 1.566 +13 -2.6162719037E+00 5.283E-07 1.544 +Total number of SCF: 13 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6162719037E+00 (Ha/atom) +Total free energy : -5.2325438073E+01 (Ha) +Band structure energy : -9.1019998217E+00 (Ha) +Exchange correlation energy : -2.0481200717E+01 (Ha) +Self and correction energy : -7.6945217074E+01 (Ha) +-Entropy*kb*T : -1.4182513240E-01 (Ha) +Fermi level : -2.8641026405E-02 (Ha) +RMS force : 1.1679060837E-02 (Ha/Bohr) +Maximum force : 1.5602314247E-02 (Ha/Bohr) +Time for force calculation : 0.058 (sec) +Pressure : -5.4047994225E+00 (GPa) +Maximum stress : 5.8292182257E+00 (GPa) +Time for stress calculation : 0.146 (sec) +MD step time : 22.301 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8845906383962 18.8828893679966 18.8813121399506 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248481 (Bohr) +Mesh spacing in y-direction : 0.248459 (Bohr) +Mesh spacing in z direction : 0.248438 (Bohr) +=================================================================== + Self Consistent Field (SCF#9) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6163730944E+00 3.404E-03 1.649 +2 -2.6164335166E+00 2.358E-03 1.673 +3 -2.6164376277E+00 1.485E-02 1.686 +4 -2.6164338695E+00 1.734E-03 1.655 +5 -2.6164338154E+00 6.548E-04 1.643 +6 -2.6164338045E+00 7.107E-05 1.640 +7 -2.6164338049E+00 3.069E-05 1.634 +8 -2.6164338065E+00 1.945E-05 1.639 +9 -2.6164338062E+00 1.139E-05 1.618 +10 -2.6164338064E+00 6.208E-06 1.613 +11 -2.6164338072E+00 2.350E-06 1.616 +12 -2.6164338054E+00 1.703E-06 1.571 +13 -2.6164338076E+00 2.714E-06 1.546 +14 -2.6164338067E+00 1.072E-06 1.549 +15 -2.6164338059E+00 2.536E-07 1.553 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6164338059E+00 (Ha/atom) +Total free energy : -5.2328676118E+01 (Ha) +Band structure energy : -9.1033535746E+00 (Ha) +Exchange correlation energy : -2.0486939743E+01 (Ha) +Self and correction energy : -7.6945217431E+01 (Ha) +-Entropy*kb*T : -1.4122074642E-01 (Ha) +Fermi level : -2.8708794173E-02 (Ha) +RMS force : 1.1932406428E-02 (Ha/Bohr) +Maximum force : 1.6363572047E-02 (Ha/Bohr) +Time for force calculation : 0.058 (sec) +Pressure : -5.3968434589E+00 (GPa) +Maximum stress : 5.8330492725E+00 (GPa) +Time for stress calculation : 0.146 (sec) +MD step time : 24.926 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8814405131214 18.8793037681698 18.8773230784659 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.24844 (Bohr) +Mesh spacing in y-direction : 0.248412 (Bohr) +Mesh spacing in z direction : 0.248386 (Bohr) +=================================================================== + Self Consistent Field (SCF#10) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6165562171E+00 3.458E-03 1.638 +2 -2.6166174384E+00 4.483E-03 1.667 +3 -2.6166208260E+00 1.388E-02 1.677 +4 -2.6166179224E+00 4.555E-03 1.661 +5 -2.6166174550E+00 2.060E-04 1.637 +6 -2.6166174577E+00 5.752E-05 1.634 +7 -2.6166174585E+00 3.652E-05 1.628 +8 -2.6166174598E+00 1.793E-05 1.615 +9 -2.6166174597E+00 9.949E-06 1.605 +10 -2.6166174601E+00 5.230E-06 1.598 +11 -2.6166174606E+00 2.368E-06 1.591 +12 -2.6166174587E+00 1.138E-06 1.575 +13 -2.6166174601E+00 9.392E-07 1.538 +Total number of SCF: 13 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6166174601E+00 (Ha/atom) +Total free energy : -5.2332349203E+01 (Ha) +Band structure energy : -9.1048366760E+00 (Ha) +Exchange correlation energy : -2.0493472640E+01 (Ha) +Self and correction energy : -7.6945218084E+01 (Ha) +-Entropy*kb*T : -1.4053906283E-01 (Ha) +Fermi level : -2.8781962708E-02 (Ha) +RMS force : 1.2194531494E-02 (Ha/Bohr) +Maximum force : 1.7175366261E-02 (Ha/Bohr) +Time for force calculation : 0.058 (sec) +Pressure : -5.3877342962E+00 (GPa) +Maximum stress : 5.8368465094E+00 (GPa) +Time for stress calculation : 0.146 (sec) +MD step time : 21.657 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8779476365588 18.8753240141124 18.8728902606944 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248394 (Bohr) +Mesh spacing in y-direction : 0.24836 (Bohr) +Mesh spacing in z direction : 0.248328 (Bohr) +=================================================================== + Self Consistent Field (SCF#11) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6167654829E+00 3.423E-03 1.651 +2 -2.6168265040E+00 9.364E-04 1.657 +3 -2.6168279524E+00 7.749E-03 1.670 +4 -2.6168269065E+00 6.773E-04 1.647 +5 -2.6168269311E+00 1.130E-03 1.631 +6 -2.6168268991E+00 6.724E-05 1.631 +7 -2.6168268984E+00 3.426E-05 1.614 +8 -2.6168269002E+00 2.235E-05 1.623 +9 -2.6168269002E+00 1.246E-05 1.633 +10 -2.6168269000E+00 6.287E-06 1.601 +11 -2.6168269013E+00 2.244E-06 1.603 +12 -2.6168269005E+00 1.101E-06 1.540 +13 -2.6168269016E+00 3.654E-06 1.550 +14 -2.6168269016E+00 8.079E-07 1.537 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6168269016E+00 (Ha/atom) +Total free energy : -5.2336538033E+01 (Ha) +Band structure energy : -9.1064506646E+00 (Ha) +Exchange correlation energy : -2.0500839328E+01 (Ha) +Self and correction energy : -7.6945219324E+01 (Ha) +-Entropy*kb*T : -1.3977553930E-01 (Ha) +Fermi level : -2.8860563366E-02 (Ha) +RMS force : 1.2462826726E-02 (Ha/Bohr) +Maximum force : 1.8040157502E-02 (Ha/Bohr) +Time for force calculation : 0.058 (sec) +Pressure : -5.3775255815E+00 (GPa) +Maximum stress : 5.8407056535E+00 (GPa) +Time for stress calculation : 0.146 (sec) +*************************************************************************** + Timing info +*************************************************************************** +Total walltime : 288.004 sec +___________________________________________________________________________ + +*************************************************************************** +* Material Physics & Mechanics Group, Georgia Tech * +* PI: Phanish Suryanarayana * +* List of contributors: See the documentation * +* Citation: See README.md or the documentation for details * +* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * +* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * +*************************************************************************** + diff --git a/tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.refaimd b/tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.refaimd deleted file mode 100644 index 05a48a88..00000000 --- a/tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.refaimd +++ /dev/null @@ -1,939 +0,0 @@ -:Description: - -:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr -:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu - where atu is the atomic unit of time, hbar/Ha -:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr -:Desc_MDTM: MD time. Unit=second -:Desc_TEL: Electronic temperature. Unit=Kelvin -:Desc_TIO: Ionic temperature. Unit=Kelvin -:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom -:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom -:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom - where N = number of particles, k = Boltzmann constant -:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom -:Desc_UEN: Internal energy. Unit=Ha/atom -:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom -:Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 -:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom -:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa -:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa -:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa - where N = number of particles, k = Boltzmann constant, V = volume -:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr - - -:MDSTEP: 1 -:MDTM: 60.08 -:TWIST: 0 -:TEL: 2400 -:TIO: 2400 -:TEN: -2.6048845452E+00 -:KEN: 1.0830495547E-02 -:KENIG: 1.1400521628E-02 -:FEN: -2.6157150407E+00 -:UEN: -2.6085105467E+00 -:TSEN: -7.2044939770E-03 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 - 0.0000000000E+00 0.0000000000E+00 6.2990803296E+00 - 0.0000000000E+00 0.0000000000E+00 1.2598160659E+01 - 0.0000000000E+00 6.2990803296E+00 0.0000000000E+00 - 0.0000000000E+00 6.2990803296E+00 6.2990803296E+00 - 0.0000000000E+00 6.2990803296E+00 1.2598160659E+01 - 0.0000000000E+00 1.2598160659E+01 0.0000000000E+00 - 0.0000000000E+00 1.2598160659E+01 6.2990803296E+00 - 0.0000000000E+00 1.2598160659E+01 1.2598160659E+01 - 6.2990803296E+00 0.0000000000E+00 0.0000000000E+00 - 6.2990803296E+00 0.0000000000E+00 6.2990803296E+00 - 6.2990803296E+00 0.0000000000E+00 1.2598160659E+01 - 6.2990803296E+00 6.2990803296E+00 0.0000000000E+00 - 6.2990803296E+00 6.2990803296E+00 6.2990803296E+00 - 6.2990803296E+00 6.2990803296E+00 1.2598160659E+01 - 6.2990803296E+00 1.2598160659E+01 0.0000000000E+00 - 6.2990803296E+00 1.2598160659E+01 6.2990803296E+00 - 6.2990803296E+00 1.2598160659E+01 1.2598160659E+01 - 1.2598160659E+01 0.0000000000E+00 0.0000000000E+00 - 1.2598160659E+01 0.0000000000E+00 6.2990803296E+00 -:V: - -5.4115960593E-06 6.8757504739E-04 4.3922438152E-04 - 3.8694989004E-05 -1.5727041676E-04 5.1733352092E-04 - 6.4493512096E-04 -4.5410623326E-04 -3.0784978494E-04 - -3.2920353408E-04 -1.3619507306E-04 -4.4905699411E-04 - 2.8658596847E-04 4.0521884520E-04 -3.3919761855E-05 - -1.7257170604E-04 3.6971498788E-04 -5.9862979356E-05 - -7.9421449907E-04 -5.9309718414E-04 2.6589589603E-04 - 4.2828044862E-05 1.3096756605E-04 3.9314269459E-04 - 4.5465738595E-04 -4.7430305976E-04 1.4680556482E-04 - -4.4755494676E-04 -2.7196430316E-05 -6.1824709024E-04 - 1.9833970038E-05 1.9314745507E-05 -3.0782221035E-04 - 9.7647151403E-05 -4.7512767927E-04 4.3477905793E-04 - 5.4955924937E-04 -4.6798769662E-05 3.8047920243E-04 - 7.8609552254E-04 3.4903251115E-04 -5.0995713773E-05 - -6.9672186847E-04 5.7127171699E-04 -2.9842613860E-04 - 6.0936489813E-05 -8.3800668387E-04 -5.9302851573E-05 - -3.2116552146E-04 5.9649571820E-04 -2.8067877708E-05 - -1.4190760424E-04 9.6824119483E-06 -4.3002551677E-04 - 1.9870593859E-04 1.8287976962E-04 2.8359561204E-04 - -3.6274411453E-04 -4.1742848824E-05 -1.3552040525E-04 -:F: - -3.1866105367E-03 1.4699149296E-07 3.2888340576E-04 - -3.1867928931E-03 1.5036155246E-07 -3.2888236129E-04 - 1.1727402617E-02 1.4924476618E-07 -1.0457529758E-07 - 1.2514165764E-02 -2.4253991593E-04 1.2605126089E-04 - 1.2514170596E-02 -2.4255737336E-04 -1.2589251178E-04 - 1.3273613867E-02 -5.5095418734E-05 -1.6524497619E-07 - 1.2514164926E-02 2.4239740105E-04 1.2604544471E-04 - 1.2514157248E-02 2.4240889491E-04 -1.2588697633E-04 - 1.3273634140E-02 5.4946715383E-05 -1.6602591453E-07 - 3.1913547284E-03 1.4573360938E-07 3.2898704905E-04 - 3.1910238384E-03 1.4383596470E-07 -3.2899742365E-04 - -1.1727585205E-02 1.5086235837E-07 -9.6159638771E-08 - -1.2514214748E-02 -2.4258794985E-04 1.2600779263E-04 - -1.2514202483E-02 -2.4260702571E-04 -1.2584676222E-04 - -1.3273583380E-02 -5.5075059067E-05 -1.6548822496E-07 - -1.2514189616E-02 2.4244793470E-04 1.2600433054E-04 - -1.2514186142E-02 2.4246267481E-04 -1.2584778217E-04 - -1.3273617690E-02 5.4921698445E-05 -1.6452734992E-07 - -4.5833567447E-06 1.0655915987E-08 1.1883408687E-02 - -4.1216728401E-06 -2.0262304501E-08 -1.1883172132E-02 -:LATVEC_SCALE: 1.8897259886E+01 1.8897259886E+01 1.8897259886E+01 -:STRIO: - -7.0673226472E-01 7.4793787646E-02 -1.3794693761E-01 - 7.4793787646E-02 -7.2221946268E-01 2.9489630075E-02 - -1.3794693761E-01 2.9489630075E-02 -4.5977651246E-01 -:STRESS: - 4.9507332664E+00 9.7841568854E-08 5.4718770340E-07 - 9.7841568854E-08 5.5272749228E+00 4.8669329381E-08 - 5.4718770340E-07 4.8669329381E-08 5.7978303196E+00 -:PRESIO: 6.2957607995E-01 -:PRES: -5.4252795029E+00 -:PRESIG: 6.6271166311E-01 -:MIND: -Al - Al: 6.2990803296E+00 -C - C: 6.2990803296E+00 -Al - C: 6.2990803296E+00 -:MDSTEP: 2 -:MDTM: 42.87 -:TWIST: 0 -:TEL: 2400 -:TIO: 2400.96195647902 -:TEN: -2.6048929538E+00 -:KEN: 1.0834836574E-02 -:KENIG: 1.1405091131E-02 -:FEN: -2.6157277904E+00 -:UEN: -2.6085282153E+00 -:TSEN: -7.1995750911E-03 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 1.8896924889E+01 2.8425249149E-02 1.8169533843E-02 - 1.4889631879E-03 1.8890757585E+01 6.3204559400E+00 - 2.7069969585E-02 1.8878486008E+01 1.2585433346E+01 - 1.8884084497E+01 6.2934412397E+00 1.8878699068E+01 - 1.2282690340E-02 6.3158239925E+00 6.2976734681E+00 - 1.8890586250E+01 6.3143627311E+00 1.2595685440E+01 - 1.8864860341E+01 1.2573649314E+01 1.0996861083E-02 - 2.2054212317E-03 1.2603583090E+01 6.3153287840E+00 - 1.9257371269E-02 1.2578553903E+01 1.2604229386E+01 - 6.2806885431E+00 1.8896135013E+01 1.8871711582E+01 - 6.3000109955E+00 7.9850162294E-04 6.2863429280E+00 - 6.3027094868E+00 1.8877616954E+01 1.2616134586E+01 - 6.3213647843E+00 6.2971369971E+00 1.5733882242E-02 - 6.3311435010E+00 6.3135011749E+00 6.2969675277E+00 - 6.2698155195E+00 6.3226953484E+00 1.2585822930E+01 - 6.3011644867E+00 1.2563524439E+01 1.8894812008E+01 - 6.2853678942E+00 1.2622828629E+01 6.2979153942E+00 - 6.2927522595E+00 1.2598562489E+01 1.2580382441E+01 - 1.2606374701E+01 7.5604876493E-03 1.2651831741E-02 - 1.2583163663E+01 1.8895533638E+01 6.2925499375E+00 -:V: - -8.0900378536E-06 6.8757262195E-04 4.3949919166E-04 - 3.6016230420E-05 -1.5726970734E-04 5.1705516549E-04 - 6.5479003775E-04 -4.5410442434E-04 -3.0784873158E-04 - -3.1868370296E-04 -1.3639843177E-04 -4.4894937870E-04 - 2.9710352078E-04 4.0501346468E-04 -3.4025453335E-05 - -1.6141411188E-04 3.6966730757E-04 -5.9862896326E-05 - -7.8369294476E-04 -5.9289124159E-04 2.6600085607E-04 - 5.3346489622E-05 1.3117083400E-04 3.9303542455E-04 - 4.6581267188E-04 -4.7425511671E-04 1.4680488103E-04 - -4.4487083806E-04 -2.7196206998E-05 -6.1796827270E-04 - 2.2516067905E-05 1.9314794802E-05 -3.0809760347E-04 - 8.7789328232E-05 -4.7512579106E-04 4.3477736528E-04 - 5.3903856017E-04 -4.7002500149E-05 3.8058370604E-04 - 7.7557396676E-04 3.4882729720E-04 -5.1101303494E-05 - -7.0787621434E-04 5.7122330658E-04 -2.9842517137E-04 - 5.0417633169E-05 -8.3779979091E-04 -5.9196720510E-05 - -3.3168295865E-04 5.9669730554E-04 -2.8173553285E-05 - -1.5306403577E-04 9.7285397352E-06 -4.3002406086E-04 - 1.9869654773E-04 1.8287911177E-04 3.0603260774E-04 - -3.6275055224E-04 -4.1742732334E-05 -1.5795750324E-04 -:F: - -3.2321610378E-03 7.6276383272E-04 4.9924294077E-04 - -2.8843245880E-03 -3.5044095079E-04 -1.0360646304E-05 - 1.1740820369E-02 -3.3796256101E-04 -4.4027181649E-04 - 1.2298057446E-02 -4.7081500154E-04 -4.4061449091E-05 - 1.2398540405E-02 2.5159227792E-05 1.0124678569E-04 - 1.3492021259E-02 5.8034385317E-04 7.0779804356E-05 - 1.2209897242E-02 -3.3230911131E-04 1.2938534701E-04 - 1.2719436057E-02 3.4023144306E-04 -8.2325069581E-05 - 1.3436921601E-02 -1.7201066447E-04 -1.0994003078E-04 - 2.4091689407E-03 3.8392343914E-04 -2.2184392744E-04 - 3.6240850489E-03 -3.5236170290E-04 -4.7037346341E-04 - -1.1722891986E-02 -5.2219287840E-04 6.2637554946E-04 - -1.2308641250E-02 1.2686154650E-05 4.3290214734E-04 - -1.2352053135E-02 -3.5920520326E-04 -1.0870050551E-04 - -1.3488431083E-02 5.3265594160E-04 -4.3488396211E-04 - -1.2283029185E-02 -3.3718243232E-04 2.7060955062E-04 - -1.2706366168E-02 6.1689235082E-04 3.7157786273E-05 - -1.3467273927E-02 -2.2348330234E-05 -2.6756294204E-04 - 6.4925631967E-04 -6.0678663043E-05 1.2201065257E-02 - -5.3303232721E-04 6.2851256319E-05 -1.2178441356E-02 -:LATVEC_SCALE: 1.8897259343E+01 1.8897259343E+01 1.8897259286E+01 -:STRIO: - -7.0578433881E-01 7.7359614303E-02 -1.3823827995E-01 - 7.7359614303E-02 -7.2207489871E-01 2.8998821949E-02 - -1.3823827995E-01 2.8998821949E-02 -4.6161219240E-01 -:STRESS: - 4.9428881773E+00 -1.6143813210E-03 1.5541951439E-03 - -1.6143813210E-03 5.5295721624E+00 6.0865347692E-04 - 1.5541951439E-03 6.0865347692E-04 5.8009761034E+00 -:PRESIO: 6.2982380997E-01 -:PRES: -5.4244788144E+00 -:PRESIG: 6.6297734714E-01 -:MIND: -Al - Al: 6.2556431637E+00 -C - C: 1.9904602199E+01 -Al - C: 6.2905872110E+00 -:MDSTEP: 3 -:MDTM: 49.72 -:TWIST: 0 -:TEL: 2400 -:TIO: 2405.72852098483 -:TEN: -2.6049022575E+00 -:KEN: 1.0856346681E-02 -:KENIG: 1.1427733348E-02 -:FEN: -2.6157586042E+00 -:UEN: -2.6085667955E+00 -:TSEN: -7.1918087387E-03 -:NPT_NP_HAMIL: -8.4059570675E-06 -:R: - 1.8896477048E+01 5.6876222659E-02 3.6355916591E-02 - 2.8776605116E-03 1.8884242744E+01 6.3418304034E+00 - 5.4547168070E-02 1.8859700359E+01 1.2572690685E+01 - 1.8871336262E+01 6.2877857638E+00 1.8860136629E+01 - 2.4995870063E-02 6.3325678892E+00 6.2962699634E+00 - 1.8884381077E+01 6.3296646982E+00 1.2593212349E+01 - 1.8832885413E+01 1.2549126732E+01 2.1997916134E-02 - 4.8527590077E-03 1.2609016832E+01 6.3315737317E+00 - 3.8981122306E-02 1.2558941346E+01 1.2610293726E+01 - 6.2623807949E+00 1.8895022968E+01 1.8846155671E+01 - 6.3010673854E+00 1.5847374035E-03 6.2735893316E+00 - 6.3059310145E+00 1.8857955873E+01 1.2634129385E+01 - 6.3432207437E+00 6.2951939780E+00 3.1482375043E-02 - 6.3627764002E+00 6.3279089618E+00 6.2948508067E+00 - 6.2400826337E+00 6.3463280469E+00 1.2573470028E+01 - 6.3028215930E+00 1.2528877092E+01 1.8892373001E+01 - 6.2712141314E+00 1.2647516996E+01 6.2967515819E+00 - 6.2859562191E+00 1.2598963170E+01 1.2562595014E+01 - 1.2614638835E+01 1.5116031283E-02 2.6255711288E-02 - 1.2568125110E+01 1.8893811801E+01 6.2850688955E+00 -:V: - -1.0806244633E-05 6.8817860186E-04 4.3989635449E-04 - 3.3590126059E-05 -1.5755621857E-04 5.1702004682E-04 - 6.6462471015E-04 -4.5436528556E-04 -3.0820305394E-04 - -3.0833095084E-04 -1.3678718305E-04 -4.4896348038E-04 - 3.0750927478E-04 4.0501392331E-04 -3.3938617786E-05 - -1.5006587052E-04 3.7013620236E-04 -5.9800348421E-05 - -7.7339053885E-04 -5.9314026203E-04 2.6609601699E-04 - 6.4034406112E-05 1.3145009728E-04 3.9294615483E-04 - 4.7708256415E-04 -4.7437546667E-04 1.4670497820E-04 - -4.4282321653E-04 -2.6872131544E-05 -6.1812316664E-04 - 2.5560948575E-05 1.9017649450E-05 -3.0847721344E-04 - 7.7931794482E-05 -4.7554042347E-04 4.3528162381E-04 - 5.2866565693E-04 -4.6989436647E-05 3.8092811900E-04 - 7.6515249402E-04 3.4850756879E-04 -5.1190055692E-05 - -7.1917703583E-04 5.7164182460E-04 -2.9877544661E-04 - 4.0091214972E-05 -8.3804039771E-04 -5.8966250433E-05 - -3.4234567284E-04 5.9718532279E-04 -2.8140883223E-05 - -1.6437541390E-04 9.7092591195E-06 -4.3022698145E-04 - 1.9991225504E-04 1.8275520354E-04 3.2905372530E-04 - -3.6373843811E-04 -4.1621931128E-05 -1.8094346827E-04 -:F: - -3.2817526992E-03 1.5314026557E-03 6.7296246747E-04 - -2.5830189714E-03 -6.9686914851E-04 3.0685989807E-04 - 1.1747338383E-02 -6.8495490644E-04 -8.7781574186E-04 - 1.2069831963E-02 -6.9167171643E-04 -2.1035521255E-04 - 1.2287170952E-02 2.8883434646E-04 3.2634568793E-04 - 1.3707178071E-02 1.2130960278E-03 1.4487387224E-04 - 1.1902156961E-02 -9.2394582741E-04 1.3334492383E-04 - 1.2926028748E-02 4.3614575790E-04 -4.0430151383E-05 - 1.3592478082E-02 -3.9427401119E-04 -2.2427485056E-04 - 1.6422152658E-03 7.7152046107E-04 -7.7295947000E-04 - 4.0642486802E-03 -7.0033035485E-04 -6.1370474310E-04 - -1.1713658885E-02 -1.0458898816E-03 1.2466428467E-03 - -1.2094420092E-02 2.6970482563E-04 7.4202143925E-04 - -1.2187358496E-02 -4.7843407271E-04 -9.9399409621E-05 - -1.3701265733E-02 1.1235577597E-03 -8.6704550345E-04 - -1.2053356505E-02 -9.2294634924E-04 4.1566707443E-04 - -1.2892609361E-02 9.8561336370E-04 1.9677667669E-04 - -1.3657097770E-02 -9.1046865808E-05 -5.2984372963E-04 - 1.2910546439E-03 -1.1781906356E-04 1.2554313420E-02 - -1.0651632368E-03 1.2830699980E-04 -1.2503979494E-02 -:LATVEC_SCALE: 1.8897258258E+01 1.8897258258E+01 1.8897258087E+01 -:STRIO: - -7.0600563128E-01 8.0048328584E-02 -1.3884674668E-01 - 8.0048328584E-02 -7.2286357633E-01 2.8554120123E-02 - -1.3884674668E-01 2.8554120123E-02 -4.6417430973E-01 -:STRESS: - 4.9333367532E+00 -3.2990751431E-03 2.5940348717E-03 - -3.2990751431E-03 5.5294076164E+00 1.6873696913E-03 - 2.5940348717E-03 1.6873696913E-03 5.8035203736E+00 -:PRESIO: 6.3101450578E-01 -:PRES: -5.4220882478E+00 -:PRESIG: 6.6429365653E-01 -:MIND: -Al - Al: 6.2122895269E+00 -C - C: 1.9889194553E+01 -Al - C: 6.2819851367E+00 -:MDSTEP: 4 -:MDTM: 38.81 -:TWIST: 0 -:TEL: 2400 -:TIO: 2414.12478188292 -:TEN: -2.6049124957E+00 -:KEN: 1.0894236542E-02 -:KENIG: 1.1467617412E-02 -:FEN: -2.6158067322E+00 -:UEN: -2.6086256311E+00 -:TSEN: -7.1811011075E-03 -:NPT_NP_HAMIL: -1.7623819476E-05 -:R: - 1.8895914693E+01 8.5376844121E-02 5.4563404995E-02 - 4.1764354602E-03 1.8877703962E+01 6.3632126527E+00 - 8.2429095190E-02 1.8840892720E+01 1.2559918717E+01 - 1.8859008453E+01 6.2821067825E+00 1.8841568604E+01 - 3.8134383412E-02 6.3493195448E+00 6.2948777733E+00 - 1.8878652403E+01 6.3450067187E+00 1.2590744201E+01 - 1.8801327494E+01 1.2524574756E+01 3.3002227067E-02 - 7.9488879651E-03 1.2614464687E+01 6.3478150407E+00 - 5.9174683047E-02 1.2539317184E+01 1.2616349114E+01 - 6.2441322174E+00 1.8893937327E+01 1.8820575501E+01 - 6.3022646769E+00 2.3465413660E-03 6.2608158081E+00 - 6.3087449600E+00 1.8838260372E+01 1.2652164846E+01 - 6.3646535585E+00 6.2932603923E+00 4.7254678203E-02 - 6.3939817017E+00 6.3422981408E+00 6.2927306968E+00 - 6.2098772305E+00 6.3699966449E+00 1.2561088147E+01 - 6.3040595100E+00 1.2494201652E+01 1.8889948140E+01 - 6.2566139983E+00 1.2672236157E+01 6.2955945522E+00 - 6.2786863247E+00 1.2599360275E+01 1.2544791004E+01 - 1.2623002343E+01 2.2661433017E-02 4.0837784383E-02 - 1.2553004939E+01 1.8892099652E+01 6.2766126219E+00 -:V: - -1.3561986985E-05 6.8932856183E-04 4.4037432807E-04 - 3.1412742547E-05 -1.5811048499E-04 5.1717500585E-04 - 6.7436454616E-04 -4.5485045708E-04 -3.0887939522E-04 - -2.9812642468E-04 -1.3734121595E-04 -4.4905088683E-04 - 3.1777385805E-04 4.0517602999E-04 -3.3657610187E-05 - -1.3851686844E-04 3.7108197550E-04 -5.9666696665E-05 - -7.6323434781E-04 -5.9379865045E-04 2.6615510755E-04 - 7.4884333509E-05 1.3179045569E-04 3.9283395900E-04 - 4.8841033605E-04 -4.7461237487E-04 1.4648730093E-04 - -4.4135499670E-04 -2.6218418130E-05 -6.1864969727E-04 - 2.8971341668E-05 1.8425325720E-05 -3.0893154864E-04 - 6.8072449259E-05 -4.7632469958E-04 4.3624262098E-04 - 5.1839660800E-04 -4.6753430566E-05 3.8147586597E-04 - 7.5475826743E-04 3.4803613259E-04 -5.1263398345E-05 - -7.3054803876E-04 5.7247224078E-04 -2.9944461353E-04 - 2.9953929850E-05 -8.3864919664E-04 -5.8605197657E-05 - -3.5311211517E-04 5.9789472968E-04 -2.7969915898E-05 - -1.7581973754E-04 9.6308131581E-06 -4.3058660681E-04 - 2.0230973157E-04 1.8249640402E-04 3.5268843119E-04 - -3.6567686265E-04 -4.1371426177E-05 -2.0451263575E-04 -:F: - -3.3374104158E-03 2.3013684292E-03 8.4853444030E-04 - -2.2842212160E-03 -1.0381223414E-03 6.2103518099E-04 - 1.1746618973E-02 -1.0402076004E-03 -1.3103601671E-03 - 1.1829650302E-02 -9.0380465102E-04 -3.7282008004E-04 - 1.2180001472E-02 5.4721054566E-04 5.4918514110E-04 - 1.3918976243E-02 1.8410340150E-03 2.2189134998E-04 - 1.1592659852E-02 -1.5292844145E-03 1.3697351703E-04 - 1.3133703363E-02 5.3054766054E-04 4.1763456032E-07 - 1.3739561007E-02 -6.1049565686E-04 -3.4292181641E-04 - 8.8924884958E-04 1.1620437801E-03 -1.3205757162E-03 - 4.5091579924E-03 -1.0426207868E-03 -7.5753417130E-04 - -1.1701227840E-02 -1.5693494442E-03 1.8563595220E-03 - -1.1872817468E-02 5.2599030758E-04 1.0525309966E-03 - -1.2021296924E-02 -5.9930296888E-04 -9.7585631283E-05 - -1.3910202838E-02 1.7149158762E-03 -1.2953599860E-03 - -1.1825563099E-02 -1.5114231732E-03 5.6174203395E-04 - -1.3072322047E-02 1.3467617463E-03 3.5199612043E-04 - -1.3842494405E-02 -1.5053557493E-04 -7.8606715984E-04 - 1.9241078760E-03 -1.7119882987E-04 1.2943454218E-02 - -1.5961296776E-03 1.9647308158E-04 -1.2860895427E-02 -:LATVEC_SCALE: 1.8897256630E+01 1.8897256630E+01 1.8897256287E+01 -:STRIO: - -7.0725249881E-01 8.2843457605E-02 -1.3975297322E-01 - 8.2843457605E-02 -7.2444739554E-01 2.8151175371E-02 - -1.3975297322E-01 2.8151175371E-02 -4.6738885601E-01 -:STRESS: - 4.9221767245E+00 -5.0393880161E-03 3.0671762790E-03 - -5.0393880161E-03 5.5268367331E+00 3.2257206630E-03 - 3.0671762790E-03 3.2257206630E-03 5.8055241926E+00 -:PRESIO: 6.3302958345E-01 -:PRES: -5.4181792168E+00 -:PRESIG: 6.6661229382E-01 -:MIND: -Al - Al: 6.1690003034E+00 -C - C: 1.9873235422E+01 -Al - C: 6.2732408661E+00 -:MDSTEP: 5 -:MDTM: 41.45 -:TWIST: 0 -:TEL: 2400 -:TIO: 2425.69601793755 -:TEN: -2.6049252508E+00 -:KEN: 1.0946454134E-02 -:KENIG: 1.1522583299E-02 -:FEN: -2.6158717049E+00 -:UEN: -2.6087043733E+00 -:TSEN: -7.1673316293E-03 -:NPT_NP_HAMIL: -2.6758582831E-05 -:R: - 1.8895236048E+01 1.1394750692E-01 7.2794041065E-02 - 5.3954039952E-03 1.8871130846E+01 6.3846088417E+00 - 1.1070941091E-01 1.8822054940E+01 1.2547105267E+01 - 1.8847095356E+01 6.2763981962E+00 1.8822993481E+01 - 5.1691467312E-02 6.3660842055E+00 6.2935049455E+00 - 1.8873408729E+01 6.3604071824E+00 1.2588284218E+01 - 1.8770182738E+01 1.2499977826E+01 4.4007470293E-02 - 1.1500211073E-02 1.2619928717E+01 6.3640505163E+00 - 7.9838541194E-02 1.2519678274E+01 1.2622390082E+01 - 6.2259206966E+00 1.8892891891E+01 1.8794957747E+01 - 6.3036180214E+00 3.0718593583E-03 6.2480202082E+00 - 6.3111512404E+00 1.8818516655E+01 1.2670258125E+01 - 6.3856662736E+00 6.2913455711E+00 6.3058062680E-02 - 6.4247583474E+00 6.3566613159E+00 6.2906077332E+00 - 6.1791989016E+00 6.3937164097E+00 1.2548665168E+01 - 6.3048859904E+00 1.2459485398E+01 1.8887543036E+01 - 6.2415646221E+00 1.2696993148E+01 6.2944499527E+00 - 6.2709378826E+00 1.2599751651E+01 1.2526965474E+01 - 1.2631512741E+01 3.0190850806E-02 5.6424907426E-02 - 1.2537765099E+01 1.8890402888E+01 6.2671554106E+00 -:V: - -1.6359093969E-05 6.9092009021E-04 4.4086877779E-04 - 2.9478136317E-05 -1.5890421305E-04 5.1744023562E-04 - 6.8389866431E-04 -4.5549875566E-04 -3.0982705588E-04 - -2.8804020002E-04 -1.3803240213E-04 -4.4914137468E-04 - 3.2784893756E-04 4.0543478887E-04 -3.3179533397E-05 - -1.2675451944E-04 3.7244461508E-04 -5.9450686400E-05 - -7.5311653326E-04 -5.9478891596E-04 2.6613817065E-04 - 8.5881111289E-05 1.3217081341E-04 3.9263946645E-04 - 4.9971100192E-04 -4.7488986096E-04 1.4612654771E-04 - -4.4038900913E-04 -2.5229154793E-05 -6.1945229592E-04 - 3.2745217229E-05 1.7540257659E-05 -3.0941474186E-04 - 5.8208220671E-05 -4.7740689103E-04 4.3758581655E-04 - 5.0816486487E-04 -4.6288344825E-05 3.8217091109E-04 - 7.4428454931E-04 3.4736002071E-04 -5.1319955876E-05 - -7.4187196575E-04 5.7362903724E-04 -3.0038435180E-04 - 2.0004150982E-05 -8.3950301203E-04 -5.8104197677E-05 - -3.6391932572E-04 5.9872962215E-04 -2.7660323110E-05 - -1.8736192325E-04 9.4995680025E-06 -4.3103343101E-04 - 2.0584066583E-04 1.8208279129E-04 3.7694107508E-04 - -3.6850778983E-04 -4.0980111732E-05 -2.2868296465E-04 -:F: - -3.4002325869E-03 3.0676438985E-03 1.0254460064E-03 - -1.9868326148E-03 -1.3733176146E-03 9.3030735623E-04 - 1.1737654751E-02 -1.4024946018E-03 -1.7364510393E-03 - 1.1577764528E-02 -1.1058051423E-03 -5.3119942929E-04 - 1.2076772718E-02 7.9923180834E-04 7.6926307193E-04 - 1.4127141808E-02 2.4622062491E-03 3.0185848004E-04 - 1.1283312814E-02 -2.1451738102E-03 1.3963390619E-04 - 1.3342049569E-02 6.2349800339E-04 4.0973118030E-05 - 1.3877060031E-02 -8.2048237049E-04 -4.6610947204E-04 - 1.5137138131E-04 1.5556859365E-03 -1.8597628141E-03 - 4.9591134260E-03 -1.3785850935E-03 -9.0043677290E-04 - -1.1686413699E-02 -2.0912315919E-03 2.4503380446E-03 - -1.1644891141E-02 7.7850011381E-04 1.3627591574E-03 - -1.1855299737E-02 -7.2182222402E-04 -1.0300749541E-04 - -1.4112711107E-02 2.3044885259E-03 -1.7179232050E-03 - -1.1600122672E-02 -2.0992204741E-03 7.0861333668E-04 - -1.3245118375E-02 1.6998326537E-03 5.0301683822E-04 - -1.4022810997E-02 -1.9977059691E-04 -1.0359788421E-03 - 2.5483343391E-03 -2.2055309259E-04 1.3370260846E-02 - -2.1261424376E-03 2.6736942339E-04 -1.3251601091E-02 -:LATVEC_SCALE: 1.8897254460E+01 1.8897254460E+01 1.8897253885E+01 -:STRIO: - -7.0931041379E-01 8.5718637858E-02 -1.4092414008E-01 - 8.5718637858E-02 -7.2661390536E-01 2.7783580806E-02 - -1.4092414008E-01 2.7783580806E-02 -4.7113443182E-01 -:STRESS: - 4.9094261601E+00 -6.8318931854E-03 2.9345121043E-03 - -6.8318931854E-03 5.5218260428E+00 5.2146765201E-03 - 2.9345121043E-03 5.2146765201E-03 5.8069763630E+00 -:PRESIO: 6.3568625033E-01 -:PRES: -5.4127428553E+00 -:PRESIG: 6.6980769828E-01 -:MIND: -Al - Al: 6.1257441487E+00 -C - C: 1.9856725815E+01 -Al - C: 6.2643046536E+00 -:MDSTEP: 6 -:MDTM: 40.04 -:TWIST: 0 -:TEL: 2400 -:TIO: 2439.74064655993 -:TEN: -2.6049435096E+00 -:KEN: 1.1009833420E-02 -:KENIG: 1.1589298337E-02 -:FEN: -2.6159533431E+00 -:UEN: -2.6088029729E+00 -:TSEN: -7.1503701926E-03 -:NPT_NP_HAMIL: -3.5226473786E-05 -:R: - 1.8894439261E+01 1.4260364964E-01 9.1046850755E-02 - 6.5444669649E-03 1.8864514333E+01 6.4060213641E+00 - 1.3937654800E-01 1.8803181793E+01 1.2534240551E+01 - 1.8835592617E+01 6.2706552304E+00 1.8804412999E+01 - 6.5658006557E-02 6.3828640827E+00 6.2921596462E+00 - 1.8868659041E+01 6.3758816269E+00 1.2585836129E+01 - 1.8739452294E+01 1.2475324162E+01 5.5009448651E-02 - 1.5512312626E-02 1.2625410011E+01 6.3802752420E+00 - 1.0096914242E-01 1.2500024984E+01 1.2628410003E+01 - 6.2077276794E+00 1.8891900713E+01 1.8769293682E+01 - 6.3051424266E+00 3.7487614602E-03 6.2352025673E+00 - 6.3131496718E+00 1.8798714318E+01 1.2688422765E+01 - 6.4062588630E+00 6.2894590191E+00 7.8897126074E-02 - 6.4551003605E+00 6.3709886488E+00 6.2884825555E+00 - 6.1480528473E+00 6.4174985435E+00 1.2536191278E+01 - 6.3053087836E+00 1.2424721468E+01 1.8885163712E+01 - 6.2260661304E+00 1.2721790561E+01 6.2933234661E+00 - 6.2627079308E+00 1.2600135437E+01 1.2509116703E+01 - 1.2640215327E+01 3.7697508986E-02 7.3043714411E-02 - 1.2522370247E+01 1.8888727691E+01 6.2566710519E+00 -:V: - -1.9198323376E-05 6.9282011539E-04 4.4129855992E-04 - 2.7780920453E-05 -1.5990195519E-04 5.1771521825E-04 - 6.9308591513E-04 -4.5623083943E-04 -3.1098207938E-04 - -2.7803636283E-04 -1.3882592838E-04 -4.4914803640E-04 - 3.3766927541E-04 4.0570928018E-04 -3.2501110446E-05 - -1.1476771246E-04 3.7414780883E-04 -5.9139049990E-05 - -7.4290496750E-04 -5.9600837245E-04 2.6599506035E-04 - 9.7000641184E-05 1.3256507250E-04 3.9228975262E-04 - 5.1087493900E-04 -4.7511424875E-04 1.4559219184E-04 - -4.3983106691E-04 -2.3898136961E-05 -6.2040795969E-04 - 3.6877435006E-05 1.6365476495E-05 -3.0986815323E-04 - 4.8337993805E-05 -4.7869588629E-04 4.3921531665E-04 - 4.9788931209E-04 -4.5589341007E-05 3.8294136504E-04 - 7.3360131667E-04 3.4641407152E-04 -5.1356246660E-05 - -7.5299687671E-04 5.7500297375E-04 -3.0153305497E-04 - 1.0243759254E-05 -8.4044447662E-04 -5.7452319519E-05 - -3.7468545572E-04 5.9957126285E-04 -2.7210871131E-05 - -1.9895382137E-04 9.3225237729E-06 -4.3148167967E-04 - 2.1044632306E-04 1.8148862081E-04 4.0179320460E-04 - -3.7215791109E-04 -4.0435670531E-05 -2.5345630232E-04 -:F: - -3.4701719893E-03 3.8244654931E-03 1.2020301605E-03 - -1.6895632903E-03 -1.7020461237E-03 1.2316841501E-03 - 1.1720476172E-02 -1.7701191112E-03 -2.1529242439E-03 - 1.1314193591E-02 -1.2964288406E-03 -6.8531280390E-04 - 1.1977958068E-02 1.0441823786E-03 9.8642269837E-04 - 1.4332026472E-02 3.0735847807E-03 3.8450211101E-04 - 1.0976950334E-02 -2.7674265015E-03 1.4065067142E-04 - 1.3550207497E-02 7.1499345727E-04 8.2091612122E-05 - 1.4003305444E-02 -1.0232806358E-03 -5.9379428850E-04 - -5.7072917891E-04 1.9507803061E-03 -2.3844515047E-03 - 5.4137930713E-03 -1.7069445806E-03 -1.0417723260E-03 - -1.1670321798E-02 -2.6094467009E-03 3.0232544147E-03 - -1.1411671955E-02 1.0259386657E-03 1.6710296023E-03 - -1.1691188338E-02 -8.4574742892E-04 -1.1545218610E-04 - -1.4307750149E-02 2.8895760846E-03 -2.1328748589E-03 - -1.1378612036E-02 -2.6827594457E-03 8.5618965910E-04 - -1.3409973304E-02 2.0435506930E-03 6.4975695986E-04 - -1.4196627082E-02 -2.3821719410E-04 -1.2790527602E-03 - 3.1626814991E-03 -2.6568552643E-04 1.3836888781E-02 - -2.6549830272E-03 3.4103023042E-04 -1.3678865848E-02 -:LATVEC_SCALE: 1.8897251747E+01 1.8897251747E+01 1.8897250880E+01 -:STRIO: - -7.1190785793E-01 8.8638684073E-02 -1.4231588763E-01 - 8.8638684073E-02 -7.2909178354E-01 2.7443302860E-02 - -1.4231588763E-01 2.7443302860E-02 -4.7525101822E-01 -:STRESS: - 4.8950986698E+00 -8.6697655112E-03 2.1693583460E-03 - -8.6697655112E-03 5.5143397342E+00 7.6091311161E-03 - 2.1693583460E-03 7.6091311161E-03 5.8078274294E+00 -:PRESIO: 6.3875021990E-01 -:PRES: -5.4057552778E+00 -:PRESIG: 6.7368614364E-01 -:MIND: -Al - Al: 6.0824985502E+00 -C - C: 1.9839669187E+01 -Al - C: 6.2551296094E+00 -:MDSTEP: 7 -:MDTM: 37.02 -:TWIST: 0 -:TEL: 2400 -:TIO: 2455.35579526337 -:TEN: -2.6049730272E+00 -:KEN: 1.1080300003E-02 -:KENIG: 1.1663473687E-02 -:FEN: -2.6160533272E+00 -:UEN: -2.6089232235E+00 -:TSEN: -7.1301036877E-03 -:NPT_NP_HAMIL: -4.2773492151E-05 -:R: - 1.8893522496E+01 1.7135465947E-01 1.0931724180E-01 - 7.6333476742E-03 1.8857846932E+01 6.4274481126E+00 - 1.6841268784E-01 1.8784271612E+01 1.2521317700E+01 - 1.8824497379E+01 6.2648746688E+00 1.8785832699E+01 - 8.0021940597E-02 6.3996578274E+00 6.2908501721E+00 - 1.8864412699E+01 6.3914421274E+00 1.2583404223E+01 - 1.8709143085E+01 1.2450606670E+01 6.6001751925E-02 - 1.9989569602E-02 1.2630908510E+01 6.3964811448E+00 - 1.2255797898E-01 1.2480361805E+01 1.2634400934E+01 - 6.1895387369E+00 1.8890978029E+01 1.8743580179E+01 - 6.3068525992E+00 4.3655026114E-03 6.2223655133E+00 - 6.3147400813E+00 1.8778847035E+01 1.2706667929E+01 - 6.4264278065E+00 6.2876104011E+00 9.4773248539E-02 - 6.4849961221E+00 6.3852674760E+00 6.2863559778E+00 - 6.1164510571E+00 6.4413493515E+00 1.2523659433E+01 - 6.3053357680E+00 1.2389910027E+01 1.8882816652E+01 - 6.2101223683E+00 1.2746625747E+01 6.2922208260E+00 - 6.2539957782E+00 1.2600510078E+01 1.2491246734E+01 - 1.2649152706E+01 4.5173511923E-02 9.0719742407E-02 - 1.2506788323E+01 1.8887080761E+01 6.2451334761E+00 -:V: - -2.2078253528E-05 6.9487380135E-04 4.4157117916E-04 - 2.6316808315E-05 -1.6106350271E-04 5.1788526464E-04 - 7.0176499623E-04 -4.5695525760E-04 -3.1226998654E-04 - -2.6807845746E-04 -1.3968226030E-04 -4.4897396648E-04 - 3.4715722462E-04 4.0590880340E-04 -3.1619157045E-05 - -1.0254974896E-04 3.7610292156E-04 -5.8717760841E-05 - -7.3245469340E-04 -5.9733653132E-04 2.6566942796E-04 - 1.0820933908E-04 1.3294394279E-04 3.9170433208E-04 - 5.2177354044E-04 -4.7518047082E-04 1.4485108113E-04 - -4.3957638550E-04 -2.2221303997E-05 -6.2137405341E-04 - 4.1358843155E-05 1.4905819076E-05 -3.1022550911E-04 - 3.8464365691E-05 -4.8008714587E-04 4.4101966809E-04 - 4.8748291253E-04 -4.4652398196E-05 3.8370487425E-04 - 7.2256721642E-04 3.4512658329E-04 -5.1367468967E-05 - -7.6374710985E-04 5.7646866818E-04 -3.0281989813E-04 - 6.7845374961E-07 -8.4129388910E-04 -5.6638032999E-05 - -3.8531332266E-04 6.0028604780E-04 -2.6620250246E-05 - -2.1053490474E-04 9.1070776038E-06 -4.3183530521E-04 - 2.1605709845E-04 1.8068508494E-04 4.2720614111E-04 - -3.7654193287E-04 -3.9725371438E-05 -2.7881877283E-04 -:F: - -3.5468694050E-03 4.5666579230E-03 1.3771773051E-03 - -1.3915488684E-03 -2.0235676646E-03 1.5221903704E-03 - 1.1695243413E-02 -2.1423055259E-03 -2.5569229020E-03 - 1.1039941211E-02 -1.4746956262E-03 -8.3491667136E-04 - 1.1883828409E-02 1.2813325372E-03 1.2000631493E-03 - 1.4534051949E-02 3.6725978149E-03 4.6982303425E-04 - 1.0675597781E-02 -3.3918171517E-03 1.3957254802E-04 - 1.3757574870E-02 8.0518655514E-04 1.2409401938E-04 - 1.4117178508E-02 -1.2175897207E-03 -7.2544856913E-04 - -1.2761114672E-03 2.3471882655E-03 -2.8898221064E-03 - 5.8730651597E-03 -2.0272103422E-03 -1.1810398108E-03 - -1.1654797478E-02 -3.1219014620E-03 3.5705581026E-03 - -1.1174701543E-02 1.2645631522E-03 1.9753360455E-03 - -1.1530527154E-02 -9.6979191597E-04 -1.3409298223E-04 - -1.4494113008E-02 3.4673372328E-03 -2.5385507633E-03 - -1.1161614870E-02 -3.2577665431E-03 1.0046357249E-03 - -1.3566271504E-02 2.3764792192E-03 7.9201767207E-04 - -1.4362906522E-02 -2.6543277654E-04 -1.5149334045E-03 - 3.7652226508E-03 -3.0697565126E-04 1.4345606067E-02 - -3.1822421318E-03 4.1771168024E-04 -1.4145346829E-02 -:LATVEC_SCALE: 1.8897248489E+01 1.8897248489E+01 1.8897247268E+01 -:STRIO: - -7.1473472192E-01 9.1560423091E-02 -1.4387583301E-01 - 9.1560423091E-02 -7.3156906694E-01 2.7121409177E-02 - -1.4387583301E-01 2.7121409177E-02 -4.7955098787E-01 -:STRESS: - 4.8793490496E+00 -1.0543540387E-02 7.2178245994E-04 - -1.0543540387E-02 5.5045073167E+00 1.0377180225E-02 - 7.2178245994E-04 1.0377180225E-02 5.8082137027E+00 -:PRESIO: 6.4195159224E-01 -:PRES: -5.3973566896E+00 -:PRESIG: 6.7799832165E-01 -:MIND: -Al - Al: 6.0392514645E+00 -C - C: 1.9822072162E+01 -Al - C: 6.2456722309E+00 -:MDSTEP: 8 -:MDTM: 34.90 -:TWIST: 0 -:TEL: 2400 -:TIO: 2471.50063589255 -:TEN: -2.6050189598E+00 -:KEN: 1.1153156930E-02 -:KENIG: 1.1740165189E-02 -:FEN: -2.6161721168E+00 -:UEN: -2.6090656190E+00 -:TSEN: -7.1064978033E-03 -:NPT_NP_HAMIL: -5.1065981520E-05 -:R: - 1.8892484026E+01 2.0020318129E-01 1.2759668102E-01 - 8.6716264258E-03 1.8851122887E+01 6.4488820411E+00 - 1.9779312800E-01 1.8765326630E+01 1.2508333105E+01 - 1.8813808249E+01 6.2590550021E+00 1.8767262206E+01 - 9.4767834343E-02 6.4164602408E+00 6.2895849154E+00 - 1.8860679200E+01 6.4070968992E+00 1.2580993365E+01 - 1.8679268084E+01 1.2425823513E+01 7.6975587681E-02 - 2.4934779652E-02 1.2636422922E+01 6.4126567794E+00 - 1.4459096070E-01 1.2460697698E+01 1.2640353569E+01 - 6.1713438949E+00 1.8890138203E+01 1.8717820295E+01 - 6.3087627805E+00 4.9105828488E-03 6.2095144885E+00 - 6.3159224604E+00 1.8758912984E+01 1.2724997900E+01 - 6.4461659824E+00 6.2858094038E+00 1.1068425539E-01 - 6.5144281402E+00 6.3994821813E+00 6.2842290492E+00 - 6.0844130891E+00 6.4652697265E+00 1.2511065652E+01 - 6.3049751532E+00 1.2355058980E+01 1.8880508814E+01 - 6.1937414232E+00 1.2771490371E+01 6.2911478039E+00 - 6.2448034601E+00 1.2600874342E+01 1.2473361672E+01 - 1.2658364298E+01 5.2609729050E-02 1.0947666772E-01 - 1.2490990985E+01 1.8885469332E+01 6.2325173903E+00 -:V: - -2.4995047701E-05 6.9691415830E-04 4.4158941193E-04 - 2.5082441752E-05 -1.6234552554E-04 5.1782868266E-04 - 7.0976405646E-04 -4.5757536566E-04 -3.1361003989E-04 - -2.5813294621E-04 -1.4055914530E-04 -4.4851853008E-04 - 3.5622695441E-04 4.0593845742E-04 -3.0531682263E-05 - -9.0100837318E-05 3.7821405968E-04 -5.8172765270E-05 - -7.2161959135E-04 -5.9864293657E-04 2.6510275604E-04 - 1.1946489333E-04 1.3327686793E-04 3.9080033917E-04 - 5.3226629226E-04 -4.7497841740E-04 1.4387011561E-04 - -4.3951502056E-04 -2.0196291536E-05 -6.2219773860E-04 - 4.6176247233E-05 1.3167894551E-05 -3.1041731599E-04 - 2.8594273220E-05 -4.8146899528E-04 4.4287819871E-04 - 4.7685979563E-04 -4.3477307781E-05 3.8437350503E-04 - 7.1104080671E-04 3.4342536766E-04 -5.1347697883E-05 - -7.7393316844E-04 5.7789209002E-04 -3.0416886802E-04 - -8.6809260435E-06 -8.4186009812E-04 -5.5650015191E-05 - -3.9569538024E-04 6.0073362732E-04 -2.5887735561E-05 - -2.2203462529E-04 8.8611084609E-06 -4.3199408419E-04 - 2.2259224585E-04 1.7964196479E-04 4.5312426717E-04 - -3.8156613600E-04 -3.8836451115E-05 -3.0474161160E-04 -:F: - -3.6311587386E-03 5.2879879589E-03 1.5498750814E-03 - -1.0925527357E-03 -2.3367369676E-03 1.8002037312E-03 - 1.1661845228E-02 -2.5179099160E-03 -2.9467044420E-03 - 1.0756571889E-02 -1.6375146593E-03 -9.8011141070E-04 - 1.1793518591E-02 1.5100034113E-03 1.4094711654E-03 - 1.4731830436E-02 4.2560158348E-03 5.5810065781E-04 - 1.0380547023E-02 -4.0151092809E-03 1.3593291324E-04 - 1.3963558519E-02 8.9378172232E-04 1.6726761477E-04 - 1.4217743885E-02 -1.4021848767E-03 -8.6049444065E-04 - -1.9627337393E-03 2.7443847356E-03 -3.3707681366E-03 - 6.3368675757E-03 -2.3395693910E-03 -1.3174638575E-03 - -1.1641034647E-02 -3.6260984771E-03 4.0871247421E-03 - -1.0936029421E-02 1.4913241716E-03 2.2740106265E-03 - -1.1373855789E-02 -1.0929723688E-03 -1.5871723018E-04 - -1.4669033940E-02 4.0347694228E-03 -2.9329785424E-03 - -1.0949211167E-02 -3.8203171281E-03 1.1540399729E-03 - -1.3713488209E-02 2.6979358375E-03 9.2921445669E-04 - -1.4520862205E-02 -2.8115665727E-04 -1.7429576655E-03 - 4.3541896209E-03 -3.4421534704E-04 1.4898954475E-02 - -3.7067121745E-03 4.9758197500E-04 -1.4653999712E-02 -:LATVEC_SCALE: 1.8897244681E+01 1.8897244681E+01 1.8897243042E+01 -:STRIO: - -7.1746047315E-01 9.4434936437E-02 -1.4554653971E-01 - 9.4434936437E-02 -7.3371230371E-01 2.6809034916E-02 - -1.4554653971E-01 2.6809034916E-02 -4.8383135066E-01 -:STRESS: - 4.8621631041E+00 -1.2442142324E-02 -1.4434899449E-03 - -1.2442142324E-02 5.4923085247E+00 1.3481865037E-02 - -1.4434899449E-03 1.3481865037E-02 5.8081599715E+00 -:PRESIO: 6.4500137584E-01 -:PRES: -5.3875438668E+00 -:PRESIG: 6.8245683020E-01 -:MIND: -Al - Al: 5.9960022750E+00 -C - C: 1.9803945121E+01 -Al - C: 6.2358929550E+00 -:MDSTEP: 9 -:MDTM: 30.29 -:TWIST: 0 -:TEL: 2400 -:TIO: 2487.05794063785 -:TEN: -2.6050856634E+00 -:KEN: 1.1223362480E-02 -:KENIG: 1.1814065768E-02 -:FEN: -2.6163090259E+00 -:UEN: -2.6092294634E+00 -:TSEN: -7.0795624612E-03 -:NPT_NP_HAMIL: -6.0606956243E-05 -:R: - 1.8891322292E+01 2.2914482236E-01 1.4587266294E-01 - 9.6687601839E-03 1.8844338270E+01 6.4703111097E+00 - 2.2748609992E-01 1.8746353043E+01 1.2495286522E+01 - 1.8803525099E+01 6.2531965641E+00 1.8748715208E+01 - 1.0987663245E-01 6.4332622485E+00 6.2883722947E+00 - 1.8857467793E+01 6.4228501028E+00 1.2578608986E+01 - 1.8649846073E+01 1.2400978284E+01 8.7919790118E-02 - 3.0348837628E-02 1.2641950696E+01 6.4287873741E+00 - 1.6704812279E-01 1.2441046126E+01 1.2646257304E+01 - 6.1531377353E+00 1.8889395627E+01 1.8692023490E+01 - 6.3108865881E+00 5.3728090281E-03 6.1966577794E+00 - 6.3166971800E+00 1.8738914986E+01 1.2743411837E+01 - 6.4654628731E+00 6.2840655809E+00 1.2662433480E-01 - 6.5433733456E+00 6.4136142962E+00 6.2821030611E+00 - 6.0519664136E+00 6.4892549885E+00 1.2498409135E+01 - 6.3042357041E+00 1.2320184129E+01 1.8878247591E+01 - 6.1769359080E+00 1.2796370368E+01 6.2901101582E+00 - 6.2351360680E+00 1.2601227335E+01 1.2455471714E+01 - 1.2667885942E+01 5.9995851085E-02 1.2933575815E-01 - 1.2474953900E+01 1.8883901148E+01 6.2187987928E+00 -:V: - -2.7943767630E-05 6.9877295544E-04 4.4125916506E-04 - 2.4075013147E-05 -1.6370382257E-04 5.1742697093E-04 - 7.1691319989E-04 -4.5799684869E-04 -3.1492142416E-04 - -2.4817320316E-04 -1.4141221349E-04 -4.4768559195E-04 - 3.6478988538E-04 4.0570626826E-04 -2.9238761621E-05 - -7.7431600134E-05 3.8038371398E-04 -5.7490901756E-05 - -7.1026583515E-04 -5.9979810750E-04 2.6423913714E-04 - 1.3071806341E-04 1.3353395451E-04 3.8949950438E-04 - 5.4221029635E-04 -4.7440138092E-04 1.4261904252E-04 - -4.3953816660E-04 -1.7823567881E-05 -6.2272646390E-04 - 5.1312740015E-05 1.1160093825E-05 -3.1037608037E-04 - 1.8740172471E-05 -4.8273042239E-04 4.4466799507E-04 - 4.6594330461E-04 -4.2068108599E-05 3.8486063796E-04 - 6.9889421853E-04 3.4124383237E-04 -5.1291291107E-05 - -7.8336405633E-04 5.7914023515E-04 -3.0550356800E-04 - -1.7818229361E-05 -8.4195538155E-04 -5.4478389662E-05 - -4.0572064795E-04 6.0077803561E-04 -2.5014123831E-05 - -2.3337632130E-04 8.5929849482E-06 -4.3186091117E-04 - 2.2996275350E-04 1.7833206332E-04 4.7948189028E-04 - -3.8713244189E-04 -3.7757193024E-05 -3.3118551745E-04 -:F: - -3.7224987535E-03 5.9828126238E-03 1.7198556194E-03 - -7.9151586540E-04 -2.6405504614E-03 2.0623737953E-03 - 1.1618951064E-02 -2.8956477213E-03 -3.3199096113E-03 - 1.0465100418E-02 -1.7826496997E-03 -1.1207930162E-03 - 1.1706666603E-02 1.7296608078E-03 1.6138459994E-03 - 1.4923538766E-02 4.8205450379E-03 6.4960550971E-04 - 1.0092897328E-02 -4.6338097236E-03 1.2916946457E-04 - 1.4166840383E-02 9.8024648787E-04 2.1258432115E-04 - 1.4303912079E-02 -1.5757840025E-03 -9.9897107301E-04 - -2.6292543625E-03 3.1414767054E-03 -3.8207892544E-03 - 6.8042430174E-03 -2.6423774061E-03 -1.4499526591E-03 - -1.1628520611E-02 -4.1207801040E-03 4.5665451022E-03 - -1.0697102563E-02 1.7036721057E-03 2.5654570966E-03 - -1.1222076255E-02 -1.2154274761E-03 -1.8891054788E-04 - -1.4829445666E-02 4.5896534537E-03 -3.3145436624E-03 - -1.0741271301E-02 -4.3662906306E-03 1.3036847443E-03 - -1.3850595638E-02 3.0068445644E-03 1.0616054445E-03 - -1.4669582990E-02 -2.8474246446E-04 -1.9625213395E-03 - 4.9267289402E-03 -3.7786189113E-04 1.5498357564E-02 - -4.2270145928E-03 5.8100979442E-04 -1.5206693497E-02 -:LATVEC_SCALE: 1.8897240317E+01 1.8897240317E+01 1.8897238194E+01 -:STRIO: - -7.1975802889E-01 9.7210740022E-02 -1.4726936799E-01 - 9.7210740022E-02 -7.3519176220E-01 2.6498197300E-02 - -1.4726936799E-01 2.6498197300E-02 -4.8789031093E-01 -:STRESS: - 4.8435100600E+00 -1.4362501317E-02 -4.3655392582E-03 - -1.4362501317E-02 5.4776835534E+00 1.6873947756E-02 - -4.3655392582E-03 1.6873947756E-02 5.8076183760E+00 -:PRESIO: 6.4761336734E-01 -:PRES: -5.3762706631E+00 -:PRESIG: 6.8675317066E-01 -:MIND: -Al - Al: 5.9527621081E+00 -C - C: 1.9785302461E+01 -Al - C: 6.2257565680E+00 -:MDSTEP: 10 -:MDTM: 32.46 -:TWIST: 0 -:TEL: 2400 -:TIO: 2500.91651896376 -:TEN: -2.6051773623E+00 -:KEN: 1.1285902176E-02 -:KENIG: 1.1879897027E-02 -:FEN: -2.6164632645E+00 -:UEN: -2.6094138863E+00 -:TSEN: -7.0493781814E-03 -:NPT_NP_HAMIL: -7.0806470995E-05 -:R: - 1.8890035978E+01 2.5816840046E-01 1.6412904447E-01 - 1.0634136098E-02 1.8837490948E+01 6.4917185650E+00 - 2.5745311510E-01 1.8727360738E+01 1.2482180973E+01 - 1.8793648682E+01 6.2473015325E+00 1.8730209094E+01 - 1.2532572668E-01 6.4500511906E+00 6.2872206511E+00 - 1.8854787008E+01 6.4387019244E+00 1.2576257023E+01 - 1.8620900847E+01 1.2376079732E+01 9.8821033656E-02 - 3.6230487558E-02 1.2647488099E+01 6.4448552028E+00 - 1.8990375789E-01 1.2421424720E+01 1.2652100385E+01 - 6.1349191556E+00 1.8888764576E+01 1.8666205403E+01 - 6.3132368477E+00 5.7414403760E-03 6.1838063184E+00 - 6.3170652732E+00 1.8718860245E+01 1.2761903811E+01 - 6.4843051416E+00 6.2823881749E+00 1.4258424914E-01 - 6.5718039133E+00 6.4276428335E+00 6.2799795209E+00 - 6.0191461517E+00 6.5132951847E+00 1.2485692149E+01 - 6.3031269459E+00 1.2285308700E+01 1.8876040703E+01 - 6.1597229420E+00 1.2821246363E+01 6.2891135893E+00 - 6.2250018980E+00 1.2601568539E+01 1.2437590833E+01 - 1.2677749551E+01 6.7320536776E-02 1.5031556605E-01 - 1.2458656794E+01 1.8882384418E+01 6.2039553546E+00 -:V: - -3.0917839808E-05 7.0029470929E-04 4.4049877871E-04 - 2.3293062527E-05 -1.6509651539E-04 5.1657350671E-04 - 7.2305835128E-04 -4.5813643359E-04 -3.1612878413E-04 - -2.3818406146E-04 -1.4219847896E-04 -4.4639215617E-04 - 3.7276302419E-04 4.0513124217E-04 -2.7743323450E-05 - -6.4564442401E-05 3.8251993409E-04 -5.6661127018E-05 - -6.9828538360E-04 -6.0068481193E-04 2.6303046756E-04 - 1.4191514829E-04 1.3368838651E-04 3.8773642793E-04 - 5.5147156020E-04 -4.7335535284E-04 1.4107288298E-04 - -4.3954693254E-04 -1.5107375982E-05 -6.2281894608E-04 - 5.6747784848E-05 8.8945281505E-06 -3.1004214932E-04 - 8.9212652632E-06 -4.8377140089E-04 4.4627145423E-04 - 4.5467498176E-04 -4.0433615783E-05 3.8508850449E-04 - 6.8602604166E-04 3.3852689425E-04 -5.1193702722E-05 - -7.9186318431E-04 5.8009294737E-04 -3.0675336922E-04 - -2.6712914601E-05 -8.4141167919E-04 -5.3116586397E-05 - -4.1528290649E-04 6.0029914308E-04 -2.4001603936E-05 - -2.4448233056E-04 8.3120215505E-06 -4.3135030994E-04 - 2.3807309597E-04 1.7673351699E-04 5.0621065571E-04 - -3.9314499965E-04 -3.6477459259E-05 -3.5810526913E-04 -:F: - -3.8203517115E-03 6.6461881605E-03 1.8855504866E-03 - -4.8746892269E-04 -2.9345854436E-03 2.3053444767E-03 - 1.1566165723E-02 -3.2743901761E-03 -3.6731908818E-03 - 1.0166688075E-02 -1.9100812172E-03 -1.2572688402E-03 - 1.1623167988E-02 1.9400218941E-03 1.8126879041E-03 - 1.5108230565E-02 5.3630070893E-03 7.4456291820E-04 - 9.8145174813E-03 -5.2428301635E-03 1.1904389657E-04 - 1.4366518690E-02 1.0643769318E-03 2.6047081647E-04 - 1.4374111204E-02 -1.7371784080E-03 -1.1403857477E-03 - -3.2744234411E-03 3.5375043489E-03 -4.2339903555E-03 - 7.2742542487E-03 -2.9336360632E-03 -1.5777447631E-03 - -1.1617644189E-02 -4.6050152131E-03 5.0035294016E-03 - -1.0459053170E-02 1.8993232571E-03 2.8476974835E-03 - -1.1076569913E-02 -1.3368692051E-03 -2.2426738879E-04 - -1.4973479463E-02 5.1291138565E-03 -3.6812654664E-03 - -1.0538253759E-02 -4.8918013153E-03 1.4531982072E-03 - -1.3977052333E-02 3.3013053653E-03 1.1898503135E-03 - -1.4807479971E-02 -2.7463417756E-04 -2.1736625304E-03 - 5.4798348590E-03 -4.0804348732E-04 1.6145506098E-02 - -4.7417119600E-03 6.6822396650E-04 -1.5805666028E-02 -:LATVEC_SCALE: 1.8897235388E+01 1.8897235388E+01 1.8897232711E+01 -:STRIO: - -7.2133187944E-01 9.9838037106E-02 -1.4899018777E-01 - 9.9838037106E-02 -7.3571116017E-01 2.6182434491E-02 - -1.4899018777E-01 2.6182434491E-02 -4.9154570394E-01 -:STRESS: - 4.8234466803E+00 -1.6305778679E-02 -8.0772517777E-03 - -1.6305778679E-02 5.4606769007E+00 2.0494892395E-02 - -8.0772517777E-03 2.0494892395E-02 5.8066436295E+00 -:PRESIO: 6.4952958118E-01 -:PRES: -5.3635890702E+00 -:PRESIG: 6.9058051091E-01 -:MIND: -Al - Al: 5.9095534502E+00 -C - C: 1.9766162632E+01 -Al - C: 6.2152326074E+00 diff --git a/tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.refout b/tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.refout deleted file mode 100644 index cf9b718c..00000000 --- a/tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.refout +++ /dev/null @@ -1,606 +0,0 @@ -*************************************************************************** -* SPARC (version June 24, 2024) * -* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * -* Distributed under GNU General Public License 3 (GPL) * -* Start time: Mon Jun 24 20:03:00 2024 * -*************************************************************************** - Input parameters -*************************************************************************** -LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 -LATVEC: -1.000000000000000 0.000000000000000 0.000000000000000 -0.000000000000000 1.000000000000000 0.000000000000000 -0.000000000000000 0.000000000000000 1.000000000000000 -FD_GRID: 126 126 126 -FD_ORDER: 12 -BC: P P P -KPOINT_GRID: 1 1 1 -KPOINT_SHIFT: 0 0 0 -SPIN_TYP: 0 -ELEC_TEMP_TYPE: Fermi-Dirac -ELEC_TEMP: 2400 -EXCHANGE_CORRELATION: GGA_PBE -NSTATES: 72 -CHEB_DEGREE: 42 -CHEFSI_BOUND_FLAG: 0 -CALC_STRESS: 1 -TWTIME: 1E+09 -MD_FLAG: 1 -MD_METHOD: NPT_NP -MD_TIMESTEP: 1 -MD_NSTEP: 10 -ION_VEL_DSTR: 2 -ION_VEL_DSTR_RAND: 0 -ION_TEMP: 2400 -NPT_SCALE_VECS: 1 2 3 -NPT_SCALE_CONSTRAINTS: 12 -NPT_NP_QMASS: 20000 -NPT_NP_BMASS: 400 -TARGET_PRESSURE: 0.1 GPa -MAXIT_SCF: 100 -MINIT_SCF: 2 -MAXIT_POISSON: 3000 -TOL_SCF: 1.00E-06 -POISSON_SOLVER: AAR -TOL_POISSON: 1.00E-08 -TOL_LANCZOS: 1.00E-02 -TOL_PSEUDOCHARGE: 1.00E-09 -MIXING_VARIABLE: density -MIXING_PRECOND: kerker -TOL_PRECOND: 2.25E-05 -PRECOND_KERKER_KTF: 1 -PRECOND_KERKER_THRESH: 0 -MIXING_PARAMETER: 1 -MIXING_HISTORY: 7 -PULAY_FREQUENCY: 1 -PULAY_RESTART: 0 -REFERENCE_CUTOFF: 0.5 -RHO_TRIGGER: 4 -NUM_CHEFSI: 1 -FIX_RAND: 0 -VERBOSITY: 1 -PRINT_FORCES: 1 -PRINT_ATOMS: 1 -PRINT_EIGEN: 0 -PRINT_DENSITY: 0 -PRINT_MDOUT: 1 -PRINT_VELS: 1 -PRINT_RESTART: 1 -PRINT_RESTART_FQ: 1 -PRINT_ENERGY_DENSITY: 0 -OUTPUT_FILE: Al18C2_NPTNP_aeqb_c/temp_run/Al18C2_NPTNP_aeqb_c -*************************************************************************** - Cell -*************************************************************************** -Lattice vectors (Bohr): -18.897259886000001 0.000000000000000 0.000000000000000 -0.000000000000000 18.897259886000001 0.000000000000000 -0.000000000000000 0.000000000000000 18.897259886000001 -Volume: 6.7483330373E+03 (Bohr^3) -Density: 7.5528236408E-02 (amu/Bohr^3), 8.4635982984E-01 (g/cc) -*************************************************************************** - Parallelization -*************************************************************************** -NP_SPIN_PARAL: 1 -NP_KPOINT_PARAL: 1 -NP_BAND_PARAL: 24 -NP_DOMAIN_PARAL: 1 2 2 -NP_DOMAIN_PHI_PARAL: 4 4 6 -EIG_SERIAL_MAXNS: 1500 -*************************************************************************** - Initialization -*************************************************************************** -Number of processors : 96 -Mesh spacing : 0.149978 (Bohr) -Number of symmetry adapted k-points: 1 -Output printed to : Al18C2_NPTNP_aeqb_c/temp_run/Al18C2_NPTNP_aeqb_c.out -MD output printed to : Al18C2_NPTNP_aeqb_c/temp_run/Al18C2_NPTNP_aeqb_c.aimd -Total number of atom types : 2 -Total number of atoms : 20 -Total number of electrons : 62 -Atom type 1 (valence electrons) : Al 3 -Pseudopotential : ../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 -Atomic mass : 26.9815385 -Pseudocharge radii of atom type 1 : 6.90 6.90 6.90 (x, y, z dir) -Number of atoms of type 1 : 18 -Atom type 2 (valence electrons) : C 4 -Pseudopotential : ../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 -Atomic mass : 12.011 -Pseudocharge radii of atom type 2 : 6.90 6.90 6.90 (x, y, z dir) -Number of atoms of type 2 : 2 -Estimated total memory usage : 8.13 GB -Estimated memory per processor : 86.74 MB -WARNING: Atoms are too close to boundary for b calculation. -=================================================================== - Self Consistent Field (SCF#1) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.5791960051E+00 2.171E-01 7.939 -2 -2.6335646653E+00 5.866E-01 2.460 -3 -2.6175417926E+00 2.849E-01 2.387 -4 -2.6168398332E+00 2.580E-01 2.421 -5 -2.6173118751E+00 2.240E-01 2.401 -6 -2.6158812384E+00 9.285E-02 2.387 -7 -2.6164697233E+00 1.778E-01 2.379 -8 -2.6157101921E+00 1.302E-02 2.344 -9 -2.6157145163E+00 1.250E-02 2.381 -10 -2.6157188479E+00 1.418E-02 2.395 -11 -2.6157152271E+00 7.979E-03 2.330 -12 -2.6157145512E+00 1.460E-03 2.294 -13 -2.6157148643E+00 1.051E-03 2.274 -14 -2.6157149469E+00 2.761E-04 2.869 -15 -2.6157150140E+00 1.650E-04 2.264 -16 -2.6157150364E+00 1.108E-04 2.187 -17 -2.6157150391E+00 4.107E-05 2.327 -18 -2.6157150411E+00 2.548E-05 2.146 -19 -2.6157150402E+00 2.152E-05 2.234 -20 -2.6157150406E+00 6.419E-06 1.818 -21 -2.6157150409E+00 3.255E-06 2.081 -22 -2.6157150407E+00 1.807E-06 2.060 -23 -2.6157150407E+00 9.585E-07 2.018 -Total number of SCF: 23 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6157150407E+00 (Ha/atom) -Total free energy : -5.2314300814E+01 (Ha) -Band structure energy : -9.0955901268E+00 (Ha) -Exchange correlation energy : -2.0462212490E+01 (Ha) -Self and correction energy : -7.6945325391E+01 (Ha) --Entropy*kb*T : -1.4408987954E-01 (Ha) -Fermi level : -2.8344071508E-02 (Ha) -RMS force : 1.0663862651E-02 (Ha/Bohr) -Maximum force : 1.3273747868E-02 (Ha/Bohr) -Time for force calculation : 0.108 (sec) -Pressure : -5.4252795029E+00 (GPa) -Maximum stress : 5.7978303196E+00 (GPa) -Time for stress calculation : 0.176 (sec) -MD step time : 60.077 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972593431804 18.8972593431804 18.8972592863642 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149978 (Bohr) -Mesh spacing in y-direction : 0.149978 (Bohr) -Mesh spacing in z direction : 0.149978 (Bohr) -=================================================================== - Self Consistent Field (SCF#2) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6159342678E+00 3.741E-02 2.468 -2 -2.6165033154E+00 1.869E-01 2.422 -3 -2.6157840036E+00 5.259E-02 2.415 -4 -2.6159155502E+00 9.114E-02 2.441 -5 -2.6157280664E+00 3.543E-03 2.365 -6 -2.6157269784E+00 2.056E-03 2.301 -7 -2.6157270864E+00 1.067E-03 1.509 -8 -2.6157273726E+00 5.789E-04 2.277 -9 -2.6157275923E+00 3.468E-04 2.297 -10 -2.6157277297E+00 1.603E-04 2.279 -11 -2.6157277771E+00 1.066E-04 2.194 -12 -2.6157277854E+00 6.889E-05 2.153 -13 -2.6157277862E+00 4.664E-05 2.147 -14 -2.6157277874E+00 1.274E-05 2.156 -15 -2.6157277878E+00 9.241E-06 2.127 -16 -2.6157277874E+00 3.492E-06 2.104 -17 -2.6157277892E+00 1.809E-06 2.166 -18 -2.6157277904E+00 6.559E-07 2.174 -Total number of SCF: 18 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6157277904E+00 (Ha/atom) -Total free energy : -5.2314555807E+01 (Ha) -Band structure energy : -9.0965391020E+00 (Ha) -Exchange correlation energy : -2.0462553551E+01 (Ha) -Self and correction energy : -7.6945325713E+01 (Ha) --Entropy*kb*T : -1.4399150182E-01 (Ha) -Fermi level : -2.8372348571E-02 (Ha) -RMS force : 1.0677467080E-02 (Ha/Bohr) -Maximum force : 1.3505947560E-02 (Ha/Bohr) -Time for force calculation : 0.117 (sec) -Pressure : -5.4244788144E+00 (GPa) -Maximum stress : 5.8009761034E+00 (GPa) -Time for stress calculation : 0.175 (sec) -MD step time : 42.872 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972582577915 18.8972582577915 18.8972580867378 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149978 (Bohr) -Mesh spacing in y-direction : 0.149978 (Bohr) -Mesh spacing in z direction : 0.149978 (Bohr) -=================================================================== - Self Consistent Field (SCF#3) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6159683986E+00 3.806E-02 2.483 -2 -2.6165670274E+00 1.900E-01 2.406 -3 -2.6158170031E+00 5.373E-02 2.391 -4 -2.6159505946E+00 9.216E-02 2.317 -5 -2.6157589212E+00 3.590E-03 1.631 -6 -2.6157577759E+00 2.148E-03 1.667 -7 -2.6157578658E+00 1.089E-03 1.501 -8 -2.6157581643E+00 5.950E-04 2.273 -9 -2.6157583925E+00 3.646E-04 1.503 -10 -2.6157585389E+00 1.642E-04 2.247 -11 -2.6157585904E+00 1.136E-04 1.443 -12 -2.6157585996E+00 6.609E-05 2.269 -13 -2.6157586003E+00 4.644E-05 1.353 -14 -2.6157586013E+00 1.391E-05 2.144 -15 -2.6157586019E+00 9.490E-06 2.155 -16 -2.6157586015E+00 3.367E-06 2.094 -17 -2.6157586030E+00 1.872E-06 2.072 -18 -2.6157586042E+00 6.706E-07 2.019 -Total number of SCF: 18 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6157586042E+00 (Ha/atom) -Total free energy : -5.2315172084E+01 (Ha) -Band structure energy : -9.0978459285E+00 (Ha) -Exchange correlation energy : -2.0463517016E+01 (Ha) -Self and correction energy : -7.6945326809E+01 (Ha) --Entropy*kb*T : -1.4383617477E-01 (Ha) -Fermi level : -2.8414334355E-02 (Ha) -RMS force : 1.0736121341E-02 (Ha/Bohr) -Maximum force : 1.3774571958E-02 (Ha/Bohr) -Time for force calculation : 0.109 (sec) -Pressure : -5.4220882478E+00 (GPa) -Maximum stress : 5.8035203736E+00 (GPa) -Time for stress calculation : 0.171 (sec) -MD step time : 49.726 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972566301107 18.8972566301107 18.8972562866224 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149978 (Bohr) -Mesh spacing in y-direction : 0.149978 (Bohr) -Mesh spacing in z direction : 0.149978 (Bohr) -=================================================================== - Self Consistent Field (SCF#4) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6156887210E+00 3.573E-03 2.278 -2 -2.6158064349E+00 5.282E-03 1.534 -3 -2.6158085907E+00 9.439E-03 2.485 -4 -2.6158067174E+00 7.214E-04 1.395 -5 -2.6158068823E+00 3.033E-03 2.191 -6 -2.6158067302E+00 1.569E-04 1.401 -7 -2.6158067281E+00 4.816E-05 2.308 -8 -2.6158067282E+00 4.375E-05 1.354 -9 -2.6158067285E+00 2.756E-05 2.269 -10 -2.6158067294E+00 9.499E-06 1.338 -11 -2.6158067300E+00 6.672E-06 2.109 -12 -2.6158067317E+00 3.260E-06 2.059 -13 -2.6158067305E+00 4.849E-06 2.075 -14 -2.6158067322E+00 9.212E-07 2.076 -Total number of SCF: 14 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6158067322E+00 (Ha/atom) -Total free energy : -5.2316134644E+01 (Ha) -Band structure energy : -9.0994679460E+00 (Ha) -Exchange correlation energy : -2.0465114932E+01 (Ha) -Self and correction energy : -7.6945327848E+01 (Ha) --Entropy*kb*T : -1.4362202215E-01 (Ha) -Fermi level : -2.8469857747E-02 (Ha) -RMS force : 1.0847669667E-02 (Ha/Bohr) -Maximum force : 1.4075249090E-02 (Ha/Bohr) -Time for force calculation : 0.109 (sec) -Pressure : -5.4181792168E+00 (GPa) -Maximum stress : 5.8055241926E+00 (GPa) -Time for stress calculation : 0.171 (sec) -MD step time : 38.837 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972544601098 18.8972544601098 18.89725388501 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149978 (Bohr) -Mesh spacing in y-direction : 0.149978 (Bohr) -Mesh spacing in z direction : 0.149978 (Bohr) -=================================================================== - Self Consistent Field (SCF#5) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6157559379E+00 3.512E-03 2.275 -2 -2.6158708726E+00 3.031E-03 2.238 -3 -2.6158756552E+00 1.516E-02 1.451 -4 -2.6158718543E+00 2.791E-03 2.193 -5 -2.6158717147E+00 9.959E-04 2.163 -6 -2.6158717026E+00 1.178E-04 1.524 -7 -2.6158717006E+00 6.249E-05 2.172 -8 -2.6158717003E+00 3.654E-05 5.851 -9 -2.6158717014E+00 2.141E-05 2.142 -10 -2.6158717018E+00 1.020E-05 2.232 -11 -2.6158717027E+00 4.740E-06 1.435 -12 -2.6158717043E+00 3.190E-06 2.066 -13 -2.6158717028E+00 2.018E-06 2.032 -14 -2.6158717046E+00 2.217E-06 2.047 -15 -2.6158717049E+00 7.359E-07 2.018 -Total number of SCF: 15 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6158717049E+00 (Ha/atom) -Total free energy : -5.2317434099E+01 (Ha) -Band structure energy : -9.1013698196E+00 (Ha) -Exchange correlation energy : -2.0467356865E+01 (Ha) -Self and correction energy : -7.6945328245E+01 (Ha) --Entropy*kb*T : -1.4334663259E-01 (Ha) -Fermi level : -2.8537683710E-02 (Ha) -RMS force : 1.1008697230E-02 (Ha/Bohr) -Maximum force : 1.4402449177E-02 (Ha/Bohr) -Time for force calculation : 0.108 (sec) -Pressure : -5.4127428553E+00 (GPa) -Maximum stress : 5.8069763630E+00 (GPa) -Time for stress calculation : 0.170 (sec) -MD step time : 41.454 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972517469893 18.8972517469893 18.8972508798644 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149978 (Bohr) -Mesh spacing in y-direction : 0.149978 (Bohr) -Mesh spacing in z direction : 0.149978 (Bohr) -=================================================================== - Self Consistent Field (SCF#6) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6158370459E+00 3.514E-03 2.270 -2 -2.6159523144E+00 9.897E-04 2.215 -3 -2.6159534471E+00 2.609E-03 2.189 -4 -2.6159533676E+00 1.390E-03 1.652 -5 -2.6159533701E+00 1.340E-03 1.563 -6 -2.6159533441E+00 4.944E-04 1.407 -7 -2.6159533378E+00 7.063E-05 2.243 -8 -2.6159533375E+00 3.747E-05 2.162 -9 -2.6159533389E+00 2.446E-05 1.483 -10 -2.6159533391E+00 1.400E-05 2.140 -11 -2.6159533395E+00 3.988E-06 1.321 -12 -2.6159533413E+00 2.709E-06 2.069 -13 -2.6159533399E+00 1.946E-06 2.168 -14 -2.6159533417E+00 1.371E-06 2.023 -15 -2.6159533431E+00 5.129E-07 2.009 -Total number of SCF: 15 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6159533431E+00 (Ha/atom) -Total free energy : -5.2319066861E+01 (Ha) -Band structure energy : -9.1036000255E+00 (Ha) -Exchange correlation energy : -2.0470234809E+01 (Ha) -Self and correction energy : -7.6945328068E+01 (Ha) --Entropy*kb*T : -1.4300740385E-01 (Ha) -Fermi level : -2.8617827700E-02 (Ha) -RMS force : 1.1205495835E-02 (Ha/Bohr) -Maximum force : 1.4751627687E-02 (Ha/Bohr) -Time for force calculation : 0.108 (sec) -Pressure : -5.4057552778E+00 (GPa) -Maximum stress : 5.8078274294E+00 (GPa) -Time for stress calculation : 0.170 (sec) -MD step time : 40.075 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972484886197 18.8972484886197 18.8972472675005 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149978 (Bohr) -Mesh spacing in y-direction : 0.149978 (Bohr) -Mesh spacing in z direction : 0.149978 (Bohr) -=================================================================== - Self Consistent Field (SCF#7) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6159358824E+00 3.522E-03 2.267 -2 -2.6160523469E+00 2.064E-03 2.350 -3 -2.6160552259E+00 9.194E-03 2.238 -4 -2.6160533229E+00 1.039E-03 2.199 -5 -2.6160534786E+00 3.046E-03 2.173 -6 -2.6160533247E+00 1.688E-04 2.211 -7 -2.6160533230E+00 5.960E-05 2.353 -8 -2.6160533224E+00 4.859E-05 2.224 -9 -2.6160533239E+00 3.341E-05 2.224 -10 -2.6160533242E+00 1.231E-05 1.339 -11 -2.6160533246E+00 6.353E-06 2.131 -12 -2.6160533265E+00 5.413E-06 1.245 -13 -2.6160533259E+00 4.668E-06 2.053 -14 -2.6160533255E+00 1.273E-06 1.469 -15 -2.6160533272E+00 4.852E-07 2.042 -Total number of SCF: 15 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6160533272E+00 (Ha/atom) -Total free energy : -5.2321066544E+01 (Ha) -Band structure energy : -9.1061861536E+00 (Ha) -Exchange correlation energy : -2.0473754374E+01 (Ha) -Self and correction energy : -7.6945327758E+01 (Ha) --Entropy*kb*T : -1.4260207375E-01 (Ha) -Fermi level : -2.8710386973E-02 (Ha) -RMS force : 1.1427453850E-02 (Ha/Bohr) -Maximum force : 1.5117737243E-02 (Ha/Bohr) -Time for force calculation : 0.109 (sec) -Pressure : -5.3973566896E+00 (GPa) -Maximum stress : 5.8082137027E+00 (GPa) -Time for stress calculation : 0.186 (sec) -MD step time : 37.038 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972446809219 18.8972446809219 18.897243041889 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149978 (Bohr) -Mesh spacing in y-direction : 0.149978 (Bohr) -Mesh spacing in z direction : 0.149978 (Bohr) -=================================================================== - Self Consistent Field (SCF#8) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6160541227E+00 3.523E-03 2.298 -2 -2.6161710575E+00 1.905E-03 2.246 -3 -2.6161747430E+00 1.249E-02 2.224 -4 -2.6161721235E+00 1.178E-03 2.195 -5 -2.6161722129E+00 2.126E-03 1.385 -6 -2.6161721168E+00 1.708E-04 2.170 -7 -2.6161721131E+00 6.587E-05 1.356 -8 -2.6161721126E+00 3.854E-05 2.151 -9 -2.6161721140E+00 2.540E-05 2.159 -10 -2.6161721145E+00 1.133E-05 2.135 -11 -2.6161721148E+00 6.226E-06 2.121 -12 -2.6161721166E+00 8.169E-06 2.074 -13 -2.6161721148E+00 3.290E-06 2.123 -14 -2.6161721173E+00 1.186E-06 2.067 -15 -2.6161721168E+00 5.746E-07 2.013 -Total number of SCF: 15 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6161721168E+00 (Ha/atom) -Total free energy : -5.2323442335E+01 (Ha) -Band structure energy : -9.1091234636E+00 (Ha) -Exchange correlation energy : -2.0477921142E+01 (Ha) -Self and correction energy : -7.6945327695E+01 (Ha) --Entropy*kb*T : -1.4212995607E-01 (Ha) -Fermi level : -2.8814609811E-02 (Ha) -RMS force : 1.1667624781E-02 (Ha/Bohr) -Maximum force : 1.5525987760E-02 (Ha/Bohr) -Time for force calculation : 0.110 (sec) -Pressure : -5.3875438668E+00 (GPa) -Maximum stress : 5.8081599715E+00 (GPa) -Time for stress calculation : 0.170 (sec) -MD step time : 34.901 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972403172684 18.8972403172684 18.8972381939712 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149978 (Bohr) -Mesh spacing in y-direction : 0.149978 (Bohr) -Mesh spacing in z direction : 0.149978 (Bohr) -=================================================================== - Self Consistent Field (SCF#9) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6161903652E+00 3.542E-03 2.274 -2 -2.6163080286E+00 2.785E-03 2.295 -3 -2.6163120765E+00 1.266E-02 1.892 -4 -2.6163092545E+00 3.614E-03 2.180 -5 -2.6163090382E+00 1.135E-03 2.176 -6 -2.6163090245E+00 1.314E-04 2.187 -7 -2.6163090239E+00 7.249E-05 2.145 -8 -2.6163090228E+00 4.393E-05 2.134 -9 -2.6163090248E+00 2.553E-05 1.854 -10 -2.6163090246E+00 1.138E-05 1.930 -11 -2.6163090254E+00 5.576E-06 1.744 -12 -2.6163090272E+00 2.114E-06 2.150 -13 -2.6163090259E+00 9.576E-07 2.048 -Total number of SCF: 13 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6163090259E+00 (Ha/atom) -Total free energy : -5.2326180517E+01 (Ha) -Band structure energy : -9.1124096563E+00 (Ha) -Exchange correlation energy : -2.0482732350E+01 (Ha) -Self and correction energy : -7.6945327923E+01 (Ha) --Entropy*kb*T : -1.4159124922E-01 (Ha) -Fermi level : -2.8929443196E-02 (Ha) -RMS force : 1.1920403179E-02 (Ha/Bohr) -Maximum force : 1.6266976512E-02 (Ha/Bohr) -Time for force calculation : 0.108 (sec) -Pressure : -5.3762706631E+00 (GPa) -Maximum stress : 5.8076183760E+00 (GPa) -Time for stress calculation : 0.168 (sec) -MD step time : 30.295 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972353879507 18.8972353879507 18.8972327110441 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149978 (Bohr) -Mesh spacing in y-direction : 0.149978 (Bohr) -Mesh spacing in z direction : 0.149978 (Bohr) -=================================================================== - Self Consistent Field (SCF#10) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6163435989E+00 3.567E-03 2.274 -2 -2.6164622918E+00 3.316E-03 2.238 -3 -2.6164664384E+00 1.299E-02 2.252 -4 -2.6164635906E+00 4.238E-03 2.200 -5 -2.6164632701E+00 1.030E-03 1.858 -6 -2.6164632629E+00 1.370E-04 1.629 -7 -2.6164632625E+00 7.535E-05 1.350 -8 -2.6164632622E+00 4.658E-05 2.157 -9 -2.6164632637E+00 2.518E-05 2.162 -10 -2.6164632643E+00 1.171E-05 2.132 -11 -2.6164632642E+00 5.913E-06 2.352 -12 -2.6164632660E+00 2.125E-06 2.135 -13 -2.6164632645E+00 9.745E-07 2.046 -Total number of SCF: 13 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6164632645E+00 (Ha/atom) -Total free energy : -5.2329265289E+01 (Ha) -Band structure energy : -9.1160637063E+00 (Ha) -Exchange correlation energy : -2.0488173629E+01 (Ha) -Self and correction energy : -7.6945328427E+01 (Ha) --Entropy*kb*T : -1.4098756363E-01 (Ha) -Fermi level : -2.9054390130E-02 (Ha) -RMS force : 1.2181492119E-02 (Ha/Bohr) -Maximum force : 1.7054983340E-02 (Ha/Bohr) -Time for force calculation : 0.110 (sec) -Pressure : -5.3635890702E+00 (GPa) -Maximum stress : 5.8066436295E+00 (GPa) -Time for stress calculation : 0.169 (sec) -MD step time : 32.486 (sec) -*************************************************************************** - Timing info -*************************************************************************** -Total walltime : 407.953 sec -___________________________________________________________________________ - -*************************************************************************** -* Material Physics & Mechanics Group, Georgia Tech * -* PI: Phanish Suryanarayana * -* List of contributors: See the documentation * -* Citation: See README.md or the documentation for details * -* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * -* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * -*************************************************************************** - diff --git a/tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.refaimd b/tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.refaimd deleted file mode 100644 index 8d93eec0..00000000 --- a/tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.refaimd +++ /dev/null @@ -1,939 +0,0 @@ -:Description: - -:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr -:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu - where atu is the atomic unit of time, hbar/Ha -:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr -:Desc_MDTM: MD time. Unit=second -:Desc_TEL: Electronic temperature. Unit=Kelvin -:Desc_TIO: Ionic temperature. Unit=Kelvin -:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom -:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom -:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom - where N = number of particles, k = Boltzmann constant -:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom -:Desc_UEN: Internal energy. Unit=Ha/atom -:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom -:Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 -:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom -:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa -:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa -:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa - where N = number of particles, k = Boltzmann constant, V = volume -:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr - - -:MDSTEP: 1 -:MDTM: 9.86 -:TWIST: 0 -:TEL: 2400 -:TIO: 2400 -:TEN: -2.6049230388E+00 -:KEN: 1.0830495547E-02 -:KENIG: 1.1400521628E-02 -:FEN: -2.6157535344E+00 -:UEN: -2.6085495644E+00 -:TSEN: -7.2039699802E-03 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 - 0.0000000000E+00 0.0000000000E+00 6.2990803296E+00 - 0.0000000000E+00 0.0000000000E+00 1.2598160659E+01 - 0.0000000000E+00 6.2990803296E+00 0.0000000000E+00 - 0.0000000000E+00 6.2990803296E+00 6.2990803296E+00 - 0.0000000000E+00 6.2990803296E+00 1.2598160659E+01 - 0.0000000000E+00 1.2598160659E+01 0.0000000000E+00 - 0.0000000000E+00 1.2598160659E+01 6.2990803296E+00 - 0.0000000000E+00 1.2598160659E+01 1.2598160659E+01 - 6.2990803296E+00 0.0000000000E+00 0.0000000000E+00 - 6.2990803296E+00 0.0000000000E+00 6.2990803296E+00 - 6.2990803296E+00 0.0000000000E+00 1.2598160659E+01 - 6.2990803296E+00 6.2990803296E+00 0.0000000000E+00 - 6.2990803296E+00 6.2990803296E+00 6.2990803296E+00 - 6.2990803296E+00 6.2990803296E+00 1.2598160659E+01 - 6.2990803296E+00 1.2598160659E+01 0.0000000000E+00 - 6.2990803296E+00 1.2598160659E+01 6.2990803296E+00 - 6.2990803296E+00 1.2598160659E+01 1.2598160659E+01 - 1.2598160659E+01 0.0000000000E+00 0.0000000000E+00 - 1.2598160659E+01 0.0000000000E+00 6.2990803296E+00 -:V: - -5.4115960593E-06 6.8757504739E-04 4.3922438152E-04 - 3.8694989004E-05 -1.5727041676E-04 5.1733352092E-04 - 6.4493512096E-04 -4.5410623326E-04 -3.0784978494E-04 - -3.2920353408E-04 -1.3619507306E-04 -4.4905699411E-04 - 2.8658596847E-04 4.0521884520E-04 -3.3919761855E-05 - -1.7257170604E-04 3.6971498788E-04 -5.9862979356E-05 - -7.9421449907E-04 -5.9309718414E-04 2.6589589603E-04 - 4.2828044862E-05 1.3096756605E-04 3.9314269459E-04 - 4.5465738595E-04 -4.7430305976E-04 1.4680556482E-04 - -4.4755494676E-04 -2.7196430316E-05 -6.1824709024E-04 - 1.9833970038E-05 1.9314745507E-05 -3.0782221035E-04 - 9.7647151403E-05 -4.7512767927E-04 4.3477905793E-04 - 5.4955924937E-04 -4.6798769662E-05 3.8047920243E-04 - 7.8609552254E-04 3.4903251115E-04 -5.0995713773E-05 - -6.9672186847E-04 5.7127171699E-04 -2.9842613860E-04 - 6.0936489813E-05 -8.3800668387E-04 -5.9302851573E-05 - -3.2116552146E-04 5.9649571820E-04 -2.8067877708E-05 - -1.4190760424E-04 9.6824119483E-06 -4.3002551677E-04 - 1.9870593859E-04 1.8287976962E-04 2.8359561204E-04 - -3.6274411453E-04 -4.1742848824E-05 -1.3552040525E-04 -:F: - -3.1389193602E-03 1.9767598293E-07 3.3093236538E-04 - -3.1409344222E-03 1.8481711775E-07 -3.3166991070E-04 - 1.1745587453E-02 1.6110446742E-07 2.6881551194E-07 - 1.2531317867E-02 -2.4388148428E-04 1.2598848231E-04 - 1.2531360983E-02 -2.4404783870E-04 -1.2549509058E-04 - 1.3289371023E-02 -5.3780059648E-05 -1.4210441463E-07 - 1.2531307933E-02 2.4368674075E-04 1.2596695809E-04 - 1.2531340434E-02 2.4386550115E-04 -1.2546782726E-04 - 1.3289345112E-02 5.3613274240E-05 -1.4414288701E-07 - 3.1776810471E-03 1.8400378422E-07 3.3174696686E-04 - 3.1754066371E-03 1.7729783141E-07 -3.3260131530E-04 - -1.1745050094E-02 1.6014497580E-07 2.7411256810E-07 - -1.2529678143E-02 -2.4427682189E-04 1.2569268387E-04 - -1.2529589645E-02 -2.4436725252E-04 -1.2517598823E-04 - -1.3287231850E-02 -5.3611761914E-05 -1.4875200020E-07 - -1.2529671037E-02 2.4409797598E-04 1.2566959688E-04 - -1.2529582752E-02 2.4419285359E-04 -1.2515554008E-04 - -1.3287214667E-02 5.3442281157E-05 -1.4747021913E-07 - -4.4908492963E-05 1.1601367644E-08 1.1874529179E-02 - -3.9938024459E-05 -1.0053431425E-08 -1.1874921018E-02 -:LATVEC_SCALE: 1.8897259886E+01 1.8897259886E+01 1.8897259886E+01 -:STRIO: - -7.0673226472E-01 7.4793787646E-02 -1.3794693761E-01 - 7.4793787646E-02 -7.2221946268E-01 2.9489630075E-02 - -1.3794693761E-01 2.9489630075E-02 -4.5977651246E-01 -:STRESS: - 4.9784390255E+00 2.0128628277E-08 3.6374913934E-06 - 2.0128628277E-08 5.5537409260E+00 -2.4070215903E-07 - 3.6374913934E-06 -2.4070215903E-07 5.8252447875E+00 -:PRESIO: 6.2957607995E-01 -:PRES: -5.4524749130E+00 -:PRESIG: 6.6271166311E-01 -:MIND: -Al - Al: 6.2990803296E+00 -C - C: 6.2990803296E+00 -Al - C: 6.2990803296E+00 -:MDSTEP: 2 -:MDTM: 6.91 -:TWIST: 0 -:TEL: 2400 -:TIO: 2400.96425550848 -:TEN: -2.6049222412E+00 -:KEN: 1.0834846949E-02 -:KENIG: 1.1405102052E-02 -:FEN: -2.6157570882E+00 -:UEN: -2.6085580075E+00 -:TSEN: -7.1990807140E-03 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 1.8896926544E+01 2.8425250785E-02 1.8169604962E-02 - 1.4905567169E-03 1.8890757584E+01 6.3204558421E+00 - 2.7070601370E-02 1.8878486006E+01 1.2585433358E+01 - 1.8884085090E+01 6.2934411922E+00 1.8878699063E+01 - 1.2283287634E-02 6.3158239397E+00 6.2976734810E+00 - 1.8890586795E+01 6.3143627759E+00 1.2595685439E+01 - 1.8864860934E+01 1.2573649357E+01 1.0996858307E-02 - 2.2060183203E-03 1.2603583139E+01 6.3153287976E+00 - 1.9257917124E-02 1.2578553855E+01 1.2604229385E+01 - 6.2806880672E+00 1.8896135011E+01 1.8871711675E+01 - 6.3000104519E+00 7.9850278217E-04 6.2863428019E+00 - 6.3027088789E+00 1.8877616952E+01 1.2616134597E+01 - 6.3213642460E+00 6.2971369375E+00 1.5733871222E-02 - 6.3311429652E+00 6.3135011127E+00 6.2969675501E+00 - 6.2698150445E+00 6.3226953982E+00 1.2585822929E+01 - 6.3011639478E+00 1.2563524495E+01 1.8894811994E+01 - 6.2853673583E+00 1.2622828687E+01 6.2979154173E+00 - 6.2927517861E+00 1.2598562436E+01 1.2580382440E+01 - 1.2606371551E+01 7.5604876897E-03 1.2651138549E-02 - 1.2583160866E+01 1.8895533636E+01 6.2925505807E+00 -:V: - -8.0499516169E-06 6.8757265848E-04 4.3950091000E-04 - 3.6054775811E-05 -1.5726967699E-04 5.1705281788E-04 - 6.5480531697E-04 -4.5410441036E-04 -3.0784841501E-04 - -3.1866928318E-04 -1.3639955820E-04 -4.4894942750E-04 - 2.9711796730E-04 4.0501220831E-04 -3.4025118987E-05 - -1.6140086599E-04 3.6966840991E-04 -5.9862876346E-05 - -7.8367852851E-04 -5.9289015261E-04 2.6600078775E-04 - 5.3360932243E-05 1.3117205717E-04 3.9303577339E-04 - 4.6582587340E-04 -4.7425623332E-04 1.4680489812E-04 - -4.4488232735E-04 -2.7196174590E-05 -6.1796594743E-04 - 2.2502940882E-05 1.9314822757E-05 -3.0810062994E-04 - 8.7774647582E-05 -4.7512577906E-04 4.3477767266E-04 - 5.3902555786E-04 -4.7003919291E-05 3.8058343782E-04 - 7.7556102643E-04 3.4882581458E-04 -5.1100739232E-05 - -7.0788768012E-04 5.7122453148E-04 -2.9842515467E-04 - 5.0404620027E-05 -8.3779839658E-04 -5.9197001343E-05 - -3.3169589713E-04 5.9669875454E-04 -2.8172971181E-05 - -1.5307546317E-04 9.7272961453E-06 -4.3002404272E-04 - 1.9862040475E-04 1.8287911194E-04 3.0601583890E-04 - -3.6281817684E-04 -4.1742712688E-05 -1.5794192223E-04 -:F: - -3.2015121705E-03 7.6540965115E-04 4.9984739769E-04 - -2.8557329429E-03 -3.5151975891E-04 -1.0812328104E-05 - 1.1755221769E-02 -3.3738998946E-04 -4.4091442016E-04 - 1.2311172942E-02 -4.7162532920E-04 -4.3277677968E-05 - 1.2409806306E-02 2.3823893743E-05 1.0380100502E-04 - 1.3505762495E-02 5.8294400855E-04 6.9322267915E-05 - 1.2222002895E-02 -3.3436764309E-04 1.2766469430E-04 - 1.2735776098E-02 3.4267723889E-04 -8.1352928316E-05 - 1.3450930510E-02 -1.7402337215E-04 -1.1002497131E-04 - 2.3816238150E-03 3.8808484483E-04 -2.2021734686E-04 - 3.5921085025E-03 -3.5158687999E-04 -4.7091538701E-04 - -1.1738332170E-02 -5.2455949156E-04 6.2609366121E-04 - -1.2321909101E-02 8.9085488515E-06 4.3232382213E-04 - -1.2364244376E-02 -3.6352341827E-04 -1.0767373770E-04 - -1.3500644877E-02 5.3719676953E-04 -4.3626517702E-04 - -1.2294867298E-02 -3.3564887355E-04 2.7190918506E-04 - -1.2722066794E-02 6.1977962367E-04 3.6264210229E-05 - -1.3481442251E-02 -2.4346682023E-05 -2.6694477977E-04 - 6.4855860450E-04 -6.2931244776E-05 1.2181893561E-02 - -5.3221195607E-04 6.2698103783E-05 -1.2160721051E-02 -:LATVEC_SCALE: 1.8897259340E+01 1.8897259340E+01 1.8897259284E+01 -:STRIO: - -7.0578795124E-01 7.7359479038E-02 -1.3824603369E-01 - 7.7359479038E-02 -7.2207491525E-01 2.8998567417E-02 - -1.3824603369E-01 2.8998567417E-02 -4.6161034011E-01 -:STRESS: - 4.9701415456E+00 -1.6006520351E-03 1.5840116945E-03 - -1.6006520351E-03 5.5551764889E+00 6.0985612423E-04 - 1.5840116945E-03 6.0985612423E-04 5.8275378001E+00 -:PRESIO: 6.2982440220E-01 -:PRES: -5.4509519448E+00 -:PRESIG: 6.6297798226E-01 -:MIND: -Al - Al: 6.2556432455E+00 -C - C: 1.9904602618E+01 -Al - C: 6.2905920157E+00 -:MDSTEP: 3 -:MDTM: 7.24 -:TWIST: 0 -:TEL: 2400 -:TIO: 2405.73682952027 -:TEN: -2.6049231333E+00 -:KEN: 1.0856384175E-02 -:KENIG: 1.1427772816E-02 -:FEN: -2.6157795175E+00 -:UEN: -2.6085884161E+00 -:TSEN: -7.1911013875E-03 -:NPT_NP_HAMIL: 8.0036411902E-07 -:R: - 1.8896481415E+01 5.6876540605E-02 3.6356222209E-02 - 2.8818519246E-03 1.8884242649E+01 6.3418303584E+00 - 5.4549147170E-02 1.8859700225E+01 1.2572690583E+01 - 1.8871337802E+01 6.2877855954E+00 1.8860136498E+01 - 2.4997555643E-02 6.3325678675E+00 6.2962700661E+00 - 1.8884382593E+01 6.3296649969E+00 1.2593212275E+01 - 1.8832886767E+01 1.2549126553E+01 2.1997936917E-02 - 4.8545416916E-03 1.2609017055E+01 6.3315739189E+00 - 3.8982855209E-02 1.2558941025E+01 1.2610293767E+01 - 6.2623787416E+00 1.8895023098E+01 1.8846155711E+01 - 6.3010651944E+00 1.5847728010E-03 6.2735889598E+00 - 6.3059292866E+00 1.8857955630E+01 1.2634129536E+01 - 6.3432193762E+00 6.2951937114E+00 3.1482456200E-02 - 6.3627751518E+00 6.3279087993E+00 6.2948508697E+00 - 6.2400810255E+00 6.3463284885E+00 1.2573469879E+01 - 6.3028201160E+00 1.2528876983E+01 1.8892372995E+01 - 6.2712124024E+00 1.2647517404E+01 6.2967515871E+00 - 6.2859547260E+00 1.2598962995E+01 1.2562594892E+01 - 1.2614632544E+01 1.5115914680E-02 2.6252934900E-02 - 1.2568119459E+01 1.8893811769E+01 6.2850715056E+00 -:V: - -1.0740568453E-05 6.8819164420E-04 4.3990547286E-04 - 3.3653227909E-05 -1.5755956347E-04 5.1702542002E-04 - 6.6466250630E-04 -4.5437190906E-04 -3.0820810624E-04 - -3.0831033862E-04 -1.3679113363E-04 -4.4896990450E-04 - 3.0753800776E-04 4.0501789014E-04 -3.3936668334E-05 - -1.5004342660E-04 3.7014528919E-04 -5.9802490432E-05 - -7.7337806522E-04 -5.9315019628E-04 2.6609867148E-04 - 6.4063585437E-05 1.3145543561E-04 3.9295347719E-04 - 4.7711501448E-04 -4.7438570718E-04 1.4670722238E-04 - -4.4286479525E-04 -2.6869022453E-05 -6.1812915868E-04 - 2.5521345894E-05 1.9018626608E-05 -3.0848552835E-04 - 7.7905357718E-05 -4.7554985112E-04 4.3528851399E-04 - 5.2864978615E-04 -4.6994767056E-05 3.8093333286E-04 - 7.6514129526E-04 3.4850791694E-04 -5.1189430458E-05 - -7.1921003466E-04 5.7165582222E-04 -2.9878127186E-04 - 4.0068880368E-05 -8.3805084439E-04 -5.8966362748E-05 - -3.4237717106E-04 5.9719855487E-04 -2.8141493095E-05 - -1.6440132485E-04 9.7064880586E-06 -4.3023318428E-04 - 1.9983792949E-04 1.8275381386E-04 3.2900591396E-04 - -3.6381021021E-04 -4.1622852763E-05 -1.8089726462E-04 -:F: - -3.2538125865E-03 1.5374051963E-03 6.7043812749E-04 - -2.5595869308E-03 -7.0085866504E-04 3.0925439331E-04 - 1.1756910938E-02 -6.8303557947E-04 -8.7790188258E-04 - 1.2078093074E-02 -6.9043244919E-04 -2.0911795149E-04 - 1.2291976330E-02 2.8806641533E-04 3.3247791759E-04 - 1.3717860167E-02 1.2156708835E-03 1.4061444864E-04 - 1.1909950803E-02 -9.3099858238E-04 1.2917789618E-04 - 1.2941265560E-02 4.4091116638E-04 -3.9120511594E-05 - 1.3604547637E-02 -3.9667268411E-04 -2.2276655257E-04 - 1.6173602696E-03 7.8135855640E-04 -7.7199948456E-04 - 4.0363086214E-03 -6.9728302569E-04 -6.1209248113E-04 - -1.1724667549E-02 -1.0515625226E-03 1.2450332198E-03 - -1.2102809583E-02 2.6151840512E-04 7.4164655363E-04 - -1.2193730212E-02 -4.8710799731E-04 -9.7286217077E-05 - -1.3709587661E-02 1.1319955225E-03 -8.7052835503E-04 - -1.2060774907E-02 -9.2147305119E-04 4.2027664159E-04 - -1.2906827415E-02 9.9005417784E-04 1.9284566302E-04 - -1.3669296627E-02 -9.3563802095E-05 -5.2886099379E-04 - 1.2927547402E-03 -1.2244110537E-04 1.2529953014E-02 - -1.0659346674E-03 1.2844914107E-04 -1.2482043445E-02 -:LATVEC_SCALE: 1.8897258250E+01 1.8897258250E+01 1.8897258078E+01 -:STRIO: - -7.0603763590E-01 8.0052083495E-02 -1.3886730790E-01 - 8.0052083495E-02 -7.2288879458E-01 2.8556465593E-02 - -1.3886730790E-01 2.8556465593E-02 -4.6418294609E-01 -:STRESS: - 4.9598374317E+00 -3.2556199517E-03 2.6263555558E-03 - -3.2556199517E-03 5.5535302443E+00 1.6879761783E-03 - 2.6263555558E-03 1.6879761783E-03 5.8287806108E+00 -:PRESIO: 6.3103645886E-01 -:PRES: -5.4473827622E+00 -:PRESIG: 6.6429595163E-01 -:MIND: -Al - Al: 6.2122894205E+00 -C - C: 1.9889196327E+01 -Al - C: 6.2819958028E+00 -:MDSTEP: 4 -:MDTM: 4.63 -:TWIST: 0 -:TEL: 2400 -:TIO: 2414.21870848235 -:TEN: -2.6049293970E+00 -:KEN: 1.0894660405E-02 -:KENIG: 1.1468063584E-02 -:FEN: -2.6158240574E+00 -:UEN: -2.6086438650E+00 -:TSEN: -7.1801924088E-03 -:NPT_NP_HAMIL: -4.3036042220E-09 -:R: - 1.8895922726E+01 8.5378543069E-02 5.4564404412E-02 - 4.1840784255E-03 1.8877703437E+01 6.3632133855E+00 - 8.2433588867E-02 1.8840891953E+01 1.2559918115E+01 - 1.8859010851E+01 6.2821063651E+00 1.8841567830E+01 - 3.8137715671E-02 6.3493200299E+00 6.2948781360E+00 - 1.8878655083E+01 6.3450078208E+00 1.2590743830E+01 - 1.8801328925E+01 1.2524573370E+01 3.3002457311E-02 - 7.9524750900E-03 1.2614465412E+01 6.3478159343E+00 - 5.9178625466E-02 1.2539315915E+01 1.2616349429E+01 - 6.2441271736E+00 1.8893937896E+01 1.8820574751E+01 - 6.3022599020E+00 2.3467399684E-03 6.2608148621E+00 - 6.3087418167E+00 1.8838259096E+01 1.2652165621E+01 - 6.3646517171E+00 6.2932595754E+00 4.7255312330E-02 - 6.3939804597E+00 6.3422980084E+00 6.2927308093E+00 - 6.2098732952E+00 6.3699984816E+00 1.2561087356E+01 - 6.3040568768E+00 1.2494200387E+01 1.8889948229E+01 - 6.2566101461E+00 1.2672237810E+01 6.2955943673E+00 - 6.2786831724E+00 1.2599359902E+01 1.2544790259E+01 - 1.2622993293E+01 2.2661065857E-02 4.0831454145E-02 - 1.2552995920E+01 1.8892099547E+01 6.2766186636E+00 -:V: - -1.3473442607E-05 6.8937728496E-04 4.4040089663E-04 - 3.1496923334E-05 -1.5812420965E-04 5.1720537718E-04 - 6.7444035445E-04 -4.5487568303E-04 -3.0889824774E-04 - -2.9811212360E-04 -1.3735022876E-04 -4.4907622888E-04 - 3.1782074900E-04 4.0519735947E-04 -3.3652003415E-05 - -1.3849160724E-04 3.7110971815E-04 -5.9675069979E-05 - -7.6324924916E-04 -5.9384090262E-04 2.6616608927E-04 - 7.4929641827E-05 1.3180565571E-04 3.9285984095E-04 - 4.8847463284E-04 -4.7464572450E-04 1.4649732320E-04 - -4.4143707404E-04 -2.6208206807E-05 -6.1868237840E-04 - 2.8909551695E-05 1.8429682672E-05 -3.0895223821E-04 - 6.8039790377E-05 -4.7636006406E-04 4.3626754679E-04 - 5.1839672996E-04 -4.6767718121E-05 3.8149771922E-04 - 7.5477526189E-04 3.4804466001E-04 -5.1263275737E-05 - -7.3062049659E-04 5.7251877178E-04 -2.9946667417E-04 - 2.9926695550E-05 -8.3869567852E-04 -5.8604040826E-05 - -3.5317125209E-04 5.9793826613E-04 -2.7975072500E-05 - -1.7586371108E-04 9.6263553242E-06 -4.3061112083E-04 - 2.0224761908E-04 1.8249439993E-04 3.5261031304E-04 - -3.6576633307E-04 -4.1373918134E-05 -2.0443411608E-04 -:F: - -3.3140737723E-03 2.3100596354E-03 8.4272973698E-04 - -2.2679131787E-03 -1.0447377634E-03 6.2666732633E-04 - 1.1750975381E-02 -1.0372033797E-03 -1.3095920059E-03 - 1.1834680304E-02 -9.0191243631E-04 -3.7163607395E-04 - 1.2180039247E-02 5.4665874130E-04 5.5835990067E-04 - 1.3924725263E-02 1.8425611467E-03 2.1491463235E-04 - 1.1597551751E-02 -1.5385512763E-03 1.2931643514E-04 - 1.3147347675E-02 5.3814444965E-04 2.4952415439E-06 - 1.3749095503E-02 -6.1301179427E-04 -3.3906962587E-04 - 8.6607790192E-04 1.1757284070E-03 -1.3197775334E-03 - 4.4888509821E-03 -1.0371131281E-03 -7.5471397697E-04 - -1.1707220091E-02 -1.5780372248E-03 1.8533078064E-03 - -1.1877755049E-02 5.1369380388E-04 1.0530625554E-03 - -1.2022991641E-02 -6.1099748422E-04 -9.4897743524E-05 - -1.3913372109E-02 1.7256322679E-03 -1.3007229031E-03 - -1.1830109484E-02 -1.5097919026E-03 5.7016257850E-04 - -1.3084992823E-02 1.3518447573E-03 3.4458742051E-04 - -1.3852142225E-02 -1.5200999934E-04 -7.8480590385E-04 - 1.9297448091E-03 -1.7860117081E-04 1.2915086423E-02 - -1.5985184444E-03 1.9764435072E-04 -1.2835474291E-02 -:LATVEC_SCALE: 1.8897256614E+01 1.8897256614E+01 1.8897256270E+01 -:STRIO: - -7.0735573068E-01 8.2857240783E-02 -1.3979503908E-01 - 8.2857240783E-02 -7.2454265506E-01 2.8161067622E-02 - -1.3979503908E-01 2.8161067622E-02 -4.6743308342E-01 -:STRESS: - 4.9479512317E+00 -4.9569262832E-03 3.0559628956E-03 - -4.9569262832E-03 5.5495301607E+00 3.2331976857E-03 - 3.0559628956E-03 3.2331976857E-03 5.8295335006E+00 -:PRESIO: 6.3311048972E-01 -:PRES: -5.4423382977E+00 -:PRESIG: 6.6663823149E-01 -:MIND: -Al - Al: 6.1689988142E+00 -C - C: 1.9873239553E+01 -Al - C: 6.2732579850E+00 -:MDSTEP: 5 -:MDTM: 5.57 -:TWIST: 0 -:TEL: 2400 -:TIO: 2426.01564427439 -:TEN: -2.6049386451E+00 -:KEN: 1.0947896513E-02 -:KENIG: 1.1524101593E-02 -:FEN: -2.6158865416E+00 -:UEN: -2.6087203790E+00 -:TSEN: -7.1661626579E-03 -:NPT_NP_HAMIL: -5.4988836405E-06 -:R: - 1.8895248516E+01 1.1395260646E-01 7.2796629163E-02 - 5.4071392305E-03 1.8871129264E+01 6.3846118345E+00 - 1.1071826307E-01 1.8822052509E+01 1.2547103419E+01 - 1.8847098056E+01 6.2763972518E+00 1.8822990985E+01 - 5.1697253761E-02 6.3660861862E+00 6.2935058032E+00 - 1.8873412443E+01 6.3604100655E+00 1.2588283159E+01 - 1.8770182531E+01 1.2499973431E+01 4.4008306277E-02 - 1.1506279781E-02 1.2619930535E+01 6.3640531649E+00 - 7.9846257001E-02 1.2519674786E+01 1.2622391167E+01 - 6.2259107604E+00 1.8892893307E+01 1.8794954690E+01 - 6.3036100350E+00 3.0724569304E-03 6.2480180159E+00 - 6.3111466270E+00 1.8818512856E+01 1.2670260505E+01 - 6.3856650601E+00 6.2913436603E+00 6.3060218563E-02 - 6.4247589142E+00 6.3566616717E+00 6.2906078602E+00 - 6.1791906932E+00 6.3937214392E+00 1.2548662800E+01 - 6.3048821015E+00 1.2459480944E+01 1.8887543364E+01 - 6.2415573107E+00 1.2696997710E+01 6.2944492503E+00 - 6.2709322800E+00 1.2599751051E+01 1.2526963076E+01 - 1.2631501880E+01 3.0190108987E-02 5.6413726249E-02 - 1.2537751610E+01 1.8890402697E+01 6.2671663193E+00 -:V: - -1.6252222291E-05 6.9102857723E-04 4.4092394644E-04 - 2.9578222684E-05 -1.5893556045E-04 5.1751463088E-04 - 6.8403004973E-04 -4.5555604648E-04 -3.0986878946E-04 - -2.8804355827E-04 -1.3805030625E-04 -4.4919982797E-04 - 3.2792074388E-04 4.0548644251E-04 -3.3168740782E-05 - -1.2673406685E-04 3.7250191995E-04 -5.9469433799E-05 - -7.5318452480E-04 -5.9488411629E-04 2.6616293018E-04 - 8.5944387847E-05 1.3220242942E-04 3.9269690790E-04 - 4.9982124039E-04 -4.7496138314E-04 1.4615090207E-04 - -4.4052397175E-04 -2.5209366523E-05 -6.1953134614E-04 - 3.2668878858E-05 1.7550572593E-05 -3.0945655632E-04 - 5.8174962384E-05 -4.7748580372E-04 4.3764140679E-04 - 5.0819943837E-04 -4.6316473785E-05 3.8222223138E-04 - 7.4435664843E-04 3.4738510436E-04 -5.1321473244E-05 - -7.4200340833E-04 5.7372812518E-04 -3.0043372614E-04 - 1.9974627822E-05 -8.3961187226E-04 -5.8100380086E-05 - -3.6401672683E-04 5.9882289034E-04 -2.7673803305E-05 - -1.8742821625E-04 9.4945948348E-06 -4.3108961624E-04 - 2.0580485416E-04 1.8208064786E-04 3.7683808082E-04 - -3.6862972299E-04 -4.0983504832E-05 -2.2857386891E-04 -:F: - -3.3835391366E-03 3.0783211665E-03 1.0178195464E-03 - -1.9789611962E-03 -1.3821344558E-03 9.3934658111E-04 - 1.1737103402E-02 -1.3980752218E-03 -1.7355558848E-03 - 1.1580445675E-02 -1.1027299656E-03 -5.2969971686E-04 - 1.2072766809E-02 7.9843211235E-04 7.8056077241E-04 - 1.4127762567E-02 2.4618649264E-03 2.9190125192E-04 - 1.1285756991E-02 -2.1561774863E-03 1.2878450021E-04 - 1.3353567008E-02 6.3394444155E-04 4.3479968551E-05 - 1.3882743273E-02 -8.2354780452E-04 -4.5979947837E-04 - 1.2997279035E-04 1.5734787349E-03 -1.8577531585E-03 - 4.9489713880E-03 -1.3707221569E-03 -8.9629183625E-04 - -1.1687121163E-02 -2.1026613783E-03 2.4438790041E-03 - -1.1647397781E-02 7.6108792630E-04 1.3630911399E-03 - -1.1852837169E-02 -7.3645733838E-04 -9.9053146040E-05 - -1.4110992257E-02 2.3172279988E-03 -1.7245672486E-03 - -1.1602093112E-02 -2.0975198923E-03 7.2029601084E-04 - -1.3256203273E-02 1.7060358701E-03 4.9268586997E-04 - -1.4028627032E-02 -1.9936872536E-04 -1.0350509037E-03 - 2.5589223868E-03 -2.3116682149E-04 1.3339977414E-02 - -2.1302401716E-03 2.7016806993E-04 -1.3224050686E-02 -:LATVEC_SCALE: 1.8897254434E+01 1.8897254434E+01 1.8897253859E+01 -:STRIO: - -7.0953021342E-01 8.5749181984E-02 -1.4099714277E-01 - 8.5749181984E-02 -7.2682700055E-01 2.7805795426E-02 - -1.4099714277E-01 2.7805795426E-02 -4.7124260077E-01 -:STRESS: - 4.9344406904E+00 -6.7341442519E-03 2.8680683887E-03 - -6.7341442519E-03 5.5430314261E+00 5.2389537504E-03 - 2.8680683887E-03 5.2389537504E-03 5.8296993850E+00 -:PRESIO: 6.3586660491E-01 -:PRES: -5.4357238338E+00 -:PRESIG: 6.6989595954E-01 -:MIND: -Al - Al: 6.1257388507E+00 -C - C: 1.9856733260E+01 -Al - C: 6.2643280942E+00 -:MDSTEP: 6 -:MDTM: 5.61 -:TWIST: 0 -:TEL: 2400 -:TIO: 2440.43895782647 -:TEN: -2.6049551840E+00 -:KEN: 1.1012984694E-02 -:KENIG: 1.1592615467E-02 -:FEN: -2.6159681687E+00 -:UEN: -2.6088193619E+00 -:TSEN: -7.1488067912E-03 -:NPT_NP_HAMIL: -1.1414671582E-05 -:R: - 1.8894456671E+01 1.4261512031E-01 9.1052420113E-02 - 6.5606723437E-03 1.8864510788E+01 6.4060288748E+00 - 1.3939232809E-01 1.8803176137E+01 1.2534236320E+01 - 1.8835594651E+01 6.2706533449E+00 1.8804407145E+01 - 6.5667360609E-02 6.3828690545E+00 6.2921612671E+00 - 1.8868663359E+01 6.3758876815E+00 1.2585833812E+01 - 1.8739447722E+01 1.2475314138E+01 5.5011513445E-02 - 1.5521608603E-02 1.2625413780E+01 6.3802812065E+00 - 1.0098272982E-01 1.2500017385E+01 1.2628412625E+01 - 6.2077104556E+00 1.8891903500E+01 1.8769286059E+01 - 6.3051310102E+00 3.7500942289E-03 6.2351981084E+00 - 6.3131437613E+00 1.8798705800E+01 1.2688428172E+01 - 6.4062600774E+00 6.2894552372E+00 7.8902252821E-02 - 6.4551055946E+00 6.3709902873E+00 6.2884826406E+00 - 6.1480376139E+00 6.4175093653E+00 1.2536185970E+01 - 6.3053036247E+00 1.2424710726E+01 1.8885164465E+01 - 6.2260535843E+00 1.2721800498E+01 6.2933217843E+00 - 6.2626989470E+00 1.2600134657E+01 1.2509111062E+01 - 1.2640204265E+01 3.7696247887E-02 7.3026794162E-02 - 1.2522350576E+01 1.8888727477E+01 6.2566880594E+00 -:V: - -1.9079559700E-05 6.9301087748E-04 4.4139403038E-04 - 2.7890473297E-05 -1.5995762097E-04 5.1785199067E-04 - 6.9329015395E-04 -4.5633270557E-04 -3.1105597272E-04 - -2.7806692389E-04 -1.3885594265E-04 -4.4925276555E-04 - 3.3777343027E-04 4.0580320124E-04 -3.2484282797E-05 - -1.1475891581E-04 3.7424441726E-04 -5.9172408836E-05 - -7.4304955636E-04 -5.9617587656E-04 2.6603886852E-04 - 9.7083811972E-05 1.3261947891E-04 3.9239081154E-04 - 5.1104398027E-04 -4.7523862029E-04 1.4563724932E-04 - -4.4003048166E-04 -2.3865955414E-05 -6.2055098420E-04 - 3.6796552981E-05 1.6384119661E-05 -3.0993928017E-04 - 4.8309291714E-05 -4.7883504580E-04 4.3931196802E-04 - 4.9797450070E-04 -4.5636898385E-05 3.8303349122E-04 - 7.3375314454E-04 3.4646354449E-04 -5.1359882909E-05 - -7.5320653961E-04 5.7517359434E-04 -3.0161991275E-04 - 1.0213692371E-05 -8.4064085711E-04 -5.7444781035E-05 - -3.7483177819E-04 5.9973318253E-04 -2.7235898512E-05 - -1.9904601963E-04 9.3188801409E-06 -4.3158275121E-04 - 2.1045281380E-04 1.8148568435E-04 4.0167573840E-04 - -3.7232689779E-04 -4.0438064984E-05 -2.5332217994E-04 -:F: - -3.4596397221E-03 3.8371572715E-03 1.1926161361E-03 - -1.6928757792E-03 -1.7131660818E-03 1.2436364804E-03 - 1.1717193989E-02 -1.7637372899E-03 -2.1513289147E-03 - 1.1314147358E-02 -1.2924448175E-03 -6.8277908648E-04 - 1.1971718739E-02 1.0432133287E-03 9.9960294614E-04 - 1.4331107396E-02 3.0709777070E-03 3.7078504365E-04 - 1.0978942842E-02 -2.7799403646E-03 1.2736038721E-04 - 1.3558673141E-02 7.2791433316E-04 8.5136737780E-05 - 1.4003738169E-02 -1.0264706927E-03 -5.8576675542E-04 - -5.9133632454E-04 1.9676575089E-03 -2.3805271747E-03 - 5.4177121903E-03 -1.6975966230E-03 -1.0371155378E-03 - -1.1667557745E-02 -2.6226955590E-03 3.0129155757E-03 - -1.1411619363E-02 1.0088590522E-03 1.6705644148E-03 - -1.1686685581E-02 -8.6308634930E-04 -1.0947140392E-04 - -1.4304671093E-02 2.9051939421E-03 -2.1409503725E-03 - -1.1380194580E-02 -2.6815912420E-03 8.7080625152E-04 - -1.3418728621E-02 2.0514747633E-03 6.3620183944E-04 - -1.4197592861E-02 -2.3796031256E-04 -1.2783469772E-03 - 3.1781448983E-03 -2.7945184165E-04 1.3807382936E-02 - -2.6604770544E-03 3.4569326715E-04 -1.3650722526E-02 -:LATVEC_SCALE: 1.8897251708E+01 1.8897251708E+01 1.8897250841E+01 -:STRIO: - -7.1228673805E-01 8.8693309710E-02 -1.4242820605E-01 - 8.8693309710E-02 -7.2946819108E-01 2.7482183141E-02 - -1.4242820605E-01 2.7482183141E-02 -4.7545040190E-01 -:STRESS: - 4.9195859124E+00 -8.5908355443E-03 2.0691382570E-03 - -8.5908355443E-03 5.5343546945E+00 7.6172824924E-03 - 2.0691382570E-03 7.6172824924E-03 5.8293891818E+00 -:PRESIO: 6.3906844367E-01 -:PRES: -5.4277765962E+00 -:PRESIG: 6.7387897262E-01 -:MIND: -Al - Al: 6.0824858925E+00 -C - C: 1.9839680808E+01 -Al - C: 6.2551583552E+00 -:MDSTEP: 7 -:MDTM: 5.38 -:TWIST: 0 -:TEL: 2400 -:TIO: 2456.58018571217 -:TEN: -2.6049875651E+00 -:KEN: 1.1085825318E-02 -:KENIG: 1.1669289808E-02 -:FEN: -2.6160733904E+00 -:UEN: -2.6089454068E+00 -:TSEN: -7.1279836237E-03 -:NPT_NP_HAMIL: -1.8884131433E-05 -:R: - 1.8893545105E+01 1.7137628801E-01 1.0932759541E-01 - 7.6540331770E-03 1.8857840261E+01 6.4274630528E+00 - 1.6843864608E-01 1.8784260748E+01 1.2521309638E+01 - 1.8824497427E+01 6.2648713079E+00 1.8785821406E+01 - 8.0036298298E-02 6.3996677137E+00 6.2908528577E+00 - 1.8864417063E+01 6.3914530719E+00 1.2583399887E+01 - 1.8709130659E+01 1.2450587703E+01 6.6005867235E-02 - 2.0002881324E-02 1.2630915318E+01 6.3964924205E+00 - 1.2257994372E-01 1.2480347693E+01 1.2634406069E+01 - 6.1895113932E+00 1.8890982659E+01 1.8743565127E+01 - 6.3068380823E+00 4.3679695056E-03 6.2223574532E+00 - 6.3147331782E+00 1.8778831026E+01 1.2706678126E+01 - 6.4264338258E+00 6.2876039389E+00 9.4783179138E-02 - 6.4850096899E+00 6.3852714639E+00 6.2863559800E+00 - 6.1164252459E+00 6.4413692831E+00 1.2523649448E+01 - 6.3053293093E+00 1.2389888980E+01 1.8882818060E+01 - 6.2101024505E+00 1.2746644226E+01 6.2922175648E+00 - 6.2539823909E+00 1.2600509171E+01 1.2491235792E+01 - 1.2649143680E+01 4.5171533381E-02 9.0696797545E-02 - 1.2506760239E+01 1.8887080693E+01 6.2451574776E+00 -:V: - -2.1953657269E-05 6.9516379030E-04 4.4171507556E-04 - 2.6426778156E-05 -1.6114901393E-04 5.1809809099E-04 - 7.0205591641E-04 -4.5711005210E-04 -3.1238236419E-04 - -2.6814329548E-04 -1.3972674909E-04 -4.4913382832E-04 - 3.4730038154E-04 4.0605367923E-04 -3.1595337713E-05 - -1.0255485253E-04 3.7624529397E-04 -5.8770089847E-05 - -7.3269106284E-04 -5.9759067451E-04 2.6573599198E-04 - 1.0831332568E-04 1.3302611171E-04 3.9185788700E-04 - 5.2200941545E-04 -4.7536810006E-04 1.4492133164E-04 - -4.3984900608E-04 -2.2177849851E-05 -6.2159303325E-04 - 4.1286664295E-05 1.4934185096E-05 -3.1033229384E-04 - 3.8442946831E-05 -4.8029860963E-04 4.4116389690E-04 - 4.8763035949E-04 -4.4719927009E-05 3.8384554110E-04 - 7.2281500029E-04 3.4520556758E-04 -5.1372649790E-05 - -7.6405154329E-04 5.7672585921E-04 -3.0295212787E-04 - 6.4719180327E-07 -8.4159658191E-04 -5.6625482808E-05 - -3.8551604631E-04 6.0053114042E-04 -2.6660019675E-05 - -2.1065469735E-04 9.1048198975E-06 -4.3199085726E-04 - 2.1612036414E-04 1.8067930789E-04 4.2708786548E-04 - -3.7676917398E-04 -3.9724051643E-05 -2.7866745779E-04 -:F: - -3.5397795299E-03 4.5819758860E-03 1.3664170106E-03 - -1.4076439346E-03 -2.0364861549E-03 1.5351930347E-03 - 1.1693115446E-02 -2.1346703959E-03 -2.5546258797E-03 - 1.1037181530E-02 -1.4720292220E-03 -8.3112984836E-04 - 1.1877139027E-02 1.2802165088E-03 1.2145666822E-03 - 1.4536582518E-02 3.6687274366E-03 4.5263455254E-04 - 1.0679684147E-02 -3.4051128146E-03 1.2426055711E-04 - 1.3763170167E-02 8.2041961448E-04 1.2919695977E-04 - 1.4112058505E-02 -1.2203144011E-03 -7.1729297012E-04 - -1.2963022967E-03 2.3607747389E-03 -2.8848728010E-03 - 5.8923598476E-03 -2.0196500080E-03 -1.1769328300E-03 - -1.1652792938E-02 -3.1361333245E-03 3.5584014394E-03 - -1.1172560441E-02 1.2530618807E-03 1.9758298463E-03 - -1.1525581783E-02 -9.8835089085E-04 -1.2735302750E-04 - -1.4494762860E-02 3.4853445939E-03 -2.5491878153E-03 - -1.1165541742E-02 -3.2593542688E-03 1.0225430245E-03 - -1.3572581099E-02 2.3871055708E-03 7.7491443326E-04 - -1.4358670675E-02 -2.6613243370E-04 -1.5145780648E-03 - 3.7831327880E-03 -3.2317120020E-04 1.4321175808E-02 - -3.1882066763E-03 4.2377888448E-04 -1.4119160112E-02 -:LATVEC_SCALE: 1.8897248436E+01 1.8897248436E+01 1.8897247215E+01 -:STRIO: - -7.1530365819E-01 9.1644150677E-02 -1.4403342349E-01 - 9.1644150677E-02 -7.3214268940E-01 2.7179665222E-02 - -1.4403342349E-01 2.7179665222E-02 -4.7986167606E-01 -:STRESS: - 4.9036453076E+00 -1.0501158165E-02 6.1389429699E-04 - -1.0501158165E-02 5.5237047047E+00 1.0334602711E-02 - 6.1389429699E-04 1.0334602711E-02 5.8287290003E+00 -:PRESIO: 6.4243600788E-01 -:PRES: -5.4186930042E+00 -:PRESIG: 6.7833641868E-01 -:MIND: -Al - Al: 6.0392270322E+00 -C - C: 1.9822088691E+01 -Al - C: 6.2457044355E+00 -:MDSTEP: 8 -:MDTM: 4.56 -:TWIST: 0 -:TEL: 2400 -:TIO: 2473.3648587851 -:TEN: -2.6050420103E+00 -:KEN: 1.1161569621E-02 -:KENIG: 1.1749020653E-02 -:FEN: -2.6162035799E+00 -:UEN: -2.6090997112E+00 -:TSEN: -7.1038686857E-03 -:NPT_NP_HAMIL: -3.2358229763E-05 -:R: - 1.8892511943E+01 2.0023920414E-01 1.2761379958E-01 - 8.6963620484E-03 1.8851111782E+01 6.4489076189E+00 - 1.9783294834E-01 1.8765308383E+01 1.2508319622E+01 - 1.8813804809E+01 6.2590495107E+00 1.8767243213E+01 - 9.4788836408E-02 6.4164771655E+00 6.2895890002E+00 - 1.8860683182E+01 6.4071146080E+00 1.2580986104E+01 - 1.8679244070E+01 1.2425791959E+01 7.6982638536E-02 - 2.4952903046E-02 1.2636434002E+01 6.4126756269E+00 - 1.4462392979E-01 1.2460674447E+01 1.2640362269E+01 - 6.1713033975E+00 1.8890145029E+01 1.8717794672E+01 - 6.3087460730E+00 4.9145190809E-03 6.2095013155E+00 - 6.3159148149E+00 1.8758886429E+01 1.2725014821E+01 - 6.4461794515E+00 6.2857996312E+00 1.1070105312E-01 - 6.5144540329E+00 6.3994897121E+00 6.2842289274E+00 - 6.0843725824E+00 6.4653024638E+00 1.2511049003E+01 - 6.3049672387E+00 1.2355023087E+01 1.8880511196E+01 - 6.1937118384E+00 1.2771520956E+01 6.2911422318E+00 - 6.2447846667E+00 1.2600873332E+01 1.2473343139E+01 - 1.2658359874E+01 5.2606736149E-02 1.0944816253E-01 - 1.2490952009E+01 1.8885469671E+01 6.2325488506E+00 -:V: - -2.4868088461E-05 6.9730766456E-04 4.4178183719E-04 - 2.5181936377E-05 -1.6246294717E-04 5.1811979116E-04 - 7.1014554843E-04 -4.5778337893E-04 -3.1376133864E-04 - -2.5823378707E-04 -1.4061972027E-04 -4.4873363751E-04 - 3.5641086239E-04 4.0613527162E-04 -3.0499763519E-05 - -9.0115620900E-05 3.7840243178E-04 -5.8247006570E-05 - -7.2194657827E-04 -5.9898610330E-04 2.6519107976E-04 - 1.1958898215E-04 1.3338908457E-04 3.9100904082E-04 - 5.3256709062E-04 -4.7523015372E-04 1.4396589762E-04 - -4.3986153565E-04 -2.0144199670E-05 -6.2249361830E-04 - 4.6126477799E-05 1.3204257137E-05 -3.1056109921E-04 - 2.8578336836E-05 -4.8175500759E-04 4.4306995372E-04 - 4.7707120519E-04 -4.3560016194E-05 3.8456464269E-04 - 7.1138536604E-04 3.4353362868E-04 -5.1353947577E-05 - -7.7433888389E-04 5.7823952692E-04 -3.0434957744E-04 - -8.7165425288E-06 -8.4227377040E-04 -5.5629777650E-05 - -3.9595478413E-04 6.0106580155E-04 -2.5945143165E-05 - -2.2217968753E-04 8.8594315152E-06 -4.3220560286E-04 - 2.2271827919E-04 1.7962925155E-04 4.5301967936E-04 - -3.8185408896E-04 -3.8828798863E-05 -3.0458130021E-04 -:F: - -3.6250746013E-03 5.3055581157E-03 1.5404537976E-03 - -1.1197884168E-03 -2.3501914040E-03 1.8094585877E-03 - 1.1665155062E-02 -2.5101416363E-03 -2.9435459485E-03 - 1.0751357693E-02 -1.6369290877E-03 -9.7563745422E-04 - 1.1787864575E-02 1.5090008083E-03 1.4245134421E-03 - 1.4741348665E-02 4.2514556786E-03 5.3835126901E-04 - 1.0388313050E-02 -4.0290599581E-03 1.1938852322E-04 - 1.3966584714E-02 9.1043789182E-04 1.7527926608E-04 - 1.4207965190E-02 -1.4037242813E-03 -8.5346028656E-04 - -1.9812956780E-03 2.7541342646E-03 -3.3666294663E-03 - 6.3682075186E-03 -2.3370591315E-03 -1.3142025015E-03 - -1.1643939934E-02 -3.6399437526E-03 4.0764531123E-03 - -1.0932042520E-02 1.4867417814E-03 2.2772527351E-03 - -1.1369939773E-02 -1.1111684741E-03 -1.5386892792E-04 - -1.4677147683E-02 4.0547997961E-03 -2.9456691552E-03 - -1.0957422271E-02 -3.8251005990E-03 1.1743231983E-03 - -1.3717303674E-02 2.7124185819E-03 9.0937272750E-04 - -1.4512129090E-02 -2.8405874120E-04 -1.7432003250E-03 - 4.3710624050E-03 -3.6112873772E-04 1.4881638644E-02 - -3.7117752323E-03 5.0395888515E-04 -1.4630271238E-02 -:LATVEC_SCALE: 1.8897244613E+01 1.8897244613E+01 1.8897242975E+01 -:STRIO: - -7.1822397553E-01 9.4548265931E-02 -1.4575000117E-01 - 9.4548265931E-02 -7.3449023607E-01 2.6887078008E-02 - -1.4575000117E-01 2.6887078008E-02 -4.8425735148E-01 -:STRESS: - 4.8865860867E+00 -1.2424606660E-02 -1.5293145183E-03 - -1.2424606660E-02 5.5111287110E+00 1.3433778233E-02 - -1.5293145183E-03 1.3433778233E-02 5.8277968194E+00 -:PRESIO: 6.4565718769E-01 -:PRES: -5.4085038724E+00 -:PRESIG: 6.8297160642E-01 -:MIND: -Al - Al: 5.9959612764E+00 -C - C: 1.9803967122E+01 -Al - C: 6.2359263430E+00 -:MDSTEP: 9 -:MDTM: 4.62 -:TWIST: 0 -:TEL: 2400 -:TIO: 2489.58644422515 -:TEN: -2.6051202837E+00 -:KEN: 1.1234772874E-02 -:KENIG: 1.1826076710E-02 -:FEN: -2.6163550566E+00 -:UEN: -2.6092782861E+00 -:TSEN: -7.0767704983E-03 -:NPT_NP_HAMIL: -5.3268138082E-05 -:R: - 1.8891355582E+01 2.2919920781E-01 1.4589835177E-01 - 9.6967091260E-03 1.8844321482E+01 6.4703501377E+00 - 2.2754333173E-01 1.8746325473E+01 1.2495266212E+01 - 1.8803516762E+01 6.2531882814E+00 1.8748686507E+01 - 1.0990581826E-01 6.4332881341E+00 6.2883781498E+00 - 1.8857471310E+01 6.4228762459E+00 1.2578597842E+01 - 1.8649807279E+01 1.2400930773E+01 8.7930484576E-02 - 3.0372470070E-02 1.2641967263E+01 6.4288159508E+00 - 1.6709434077E-01 1.2441011394E+01 1.2646270498E+01 - 6.1530813363E+00 1.8889404885E+01 1.8691984435E+01 - 6.3108690195E+00 5.3783571005E-03 6.1966381082E+00 - 6.3166888111E+00 1.8738875086E+01 1.2743437254E+01 - 6.4654862089E+00 6.2840521395E+00 1.2664996670E-01 - 6.5434151022E+00 6.4136263974E+00 6.2821027331E+00 - 6.0519071797E+00 6.4893040077E+00 1.2498383917E+01 - 6.3042259909E+00 1.2320129163E+01 1.8878251378E+01 - 6.1768946012E+00 1.2796416455E+01 6.2901014693E+00 - 6.2351110799E+00 1.2601226163E+01 1.2455443497E+01 - 1.2667888521E+01 5.9991402079E-02 1.2930262669E-01 - 1.2474901796E+01 1.8883902202E+01 6.2188379946E+00 -:V: - -2.7815097338E-05 6.9925302956E-04 4.4148927371E-04 - 2.4153864793E-05 -1.6384925535E-04 5.1777903681E-04 - 7.1737126125E-04 -4.5824562880E-04 -3.1510255315E-04 - -2.4830406926E-04 -1.4148690723E-04 -4.4794311882E-04 - 3.6500664512E-04 4.0594407351E-04 -2.9197424409E-05 - -7.7446477206E-05 3.8060747290E-04 -5.7587445322E-05 - -7.1065961344E-04 -6.0021461411E-04 2.6434099192E-04 - 1.3085794720E-04 1.3367371937E-04 3.8975500500E-04 - 5.4255867462E-04 -4.7470324279E-04 1.4273532543E-04 - -4.3994506934E-04 -1.7765365830E-05 -6.2308310645E-04 - 5.1294776801E-05 1.1199598619E-05 -3.1054915806E-04 - 1.8723824716E-05 -4.8307761721E-04 4.4489674607E-04 - 4.6620614726E-04 -4.2158769169E-05 3.8509415653E-04 - 6.9931409808E-04 3.4137224314E-04 -5.1298835404E-05 - -7.8385724476E-04 5.7956392268E-04 -3.0572628897E-04 - -1.7862463410E-05 -8.4245985206E-04 -5.4446948585E-05 - -4.0602485543E-04 6.0118413745E-04 -2.5090566352E-05 - -2.3353801772E-04 8.5897843564E-06 -4.3211715331E-04 - 2.3014419040E-04 1.7830627139E-04 4.7939536952E-04 - -3.8746947750E-04 -3.7741529123E-05 -3.3101585986E-04 -:F: - -3.7171208058E-03 6.0020324578E-03 1.7122725404E-03 - -8.2452570005E-04 -2.6536296675E-03 2.0653378035E-03 - 1.1630162235E-02 -2.8891433169E-03 -3.3148853805E-03 - 1.0458340896E-02 -1.7849487360E-03 -1.1165433954E-03 - 1.1703094714E-02 1.7292263648E-03 1.6288885725E-03 - 1.4939026583E-02 4.8148664651E-03 6.2861551094E-04 - 1.0104971436E-02 -4.6472541265E-03 1.1276748539E-04 - 1.4167746391E-02 9.9660422308E-04 2.2184423941E-04 - 1.4291476964E-02 -1.5749373417E-03 -9.9275457756E-04 - -2.6442714125E-03 3.1458328833E-03 -3.8185161611E-03 - 6.8407298408E-03 -2.6467337938E-03 -1.4477507623E-03 - -1.1638998816E-02 -4.1331968954E-03 4.5596380793E-03 - -1.0692090292E-02 1.7094469156E-03 2.5716646514E-03 - -1.1220242194E-02 -1.2318561656E-03 -1.8694340798E-04 - -1.4844114885E-02 4.6107355320E-03 -3.3282125606E-03 - -1.0754433222E-02 -4.3760607540E-03 1.3248752749E-03 - -1.3851868042E-02 3.0260488247E-03 1.0401136285E-03 - -1.4658329039E-02 -2.9017119446E-04 -1.9632538355E-03 - 4.9401598305E-03 -3.9326476090E-04 1.5488994627E-02 - -4.2297144825E-03 5.8640308637E-04 -1.5186152332E-02 -:LATVEC_SCALE: 1.8897240233E+01 1.8897240233E+01 1.8897238111E+01 -:STRIO: - -7.2067815296E-01 9.7347900913E-02 -1.4751002451E-01 - 9.7347900913E-02 -7.3613706366E-01 2.6593510761E-02 - -1.4751002451E-01 2.6593510761E-02 -4.8840795369E-01 -:STRESS: - 4.8681696733E+00 -1.4360908422E-02 -4.3734868606E-03 - -1.4360908422E-02 5.4966693142E+00 1.6861816939E-02 - -4.3734868606E-03 1.6861816939E-02 5.8268077883E+00 -:PRESIO: 6.4840772344E-01 -:PRES: -5.3972155919E+00 -:PRESIG: 6.8745137740E-01 -:MIND: -Al - Al: 5.9527002439E+00 -C - C: 1.9785330492E+01 -Al - C: 6.2257890229E+00 -:MDSTEP: 10 -:MDTM: 5.23 -:TWIST: 0 -:TEL: 2400 -:TIO: 2503.98500367893 -:TEN: -2.6052237490E+00 -:KEN: 1.1299749347E-02 -:KENIG: 1.1894472997E-02 -:FEN: -2.6165234984E+00 -:UEN: -2.6094767434E+00 -:TSEN: -7.0467549524E-03 -:NPT_NP_HAMIL: -7.8046327634E-05 -:R: - 1.8890074714E+01 2.5824391160E-01 1.6416437610E-01 - 1.0664214595E-02 1.8837467534E+01 6.4917726971E+00 - 2.5753030872E-01 1.8727322683E+01 1.2482153058E+01 - 1.8793634471E+01 6.2472899495E+00 1.8730169482E+01 - 1.2536407985E-01 6.4500872448E+00 6.2872287006E+00 - 1.8854790370E+01 6.4387374537E+00 1.2576241104E+01 - 1.8620845554E+01 1.2376014000E+01 9.8835608470E-02 - 3.6260054190E-02 1.2647511111E+01 6.4448949979E+00 - 1.8996443268E-01 1.2421377109E+01 1.2652118712E+01 - 6.1348450345E+00 1.8888776354E+01 1.8666151114E+01 - 6.3132198507E+00 5.7484749910E-03 6.1837792874E+00 - 6.3170558694E+00 1.8718805121E+01 1.2761938833E+01 - 6.4843399142E+00 6.2823711508E+00 1.4262009014E-01 - 6.5718636910E+00 6.4276599746E+00 6.2799788960E+00 - 6.0190653165E+00 6.5133629494E+00 1.2485656971E+01 - 6.3031149210E+00 1.2285231785E+01 1.8876046454E+01 - 6.1596686475E+00 1.2821310418E+01 6.2891009748E+00 - 6.2249703949E+00 1.2601567043E+01 1.2437551605E+01 - 1.2677760872E+01 6.7313991699E-02 1.5027861573E-01 - 1.2458590198E+01 1.8882386485E+01 6.2040028086E+00 -:V: - -3.0786720229E-05 7.0082050347E-04 4.4074154695E-04 - 2.3344980653E-05 -1.6525971707E-04 5.1694992936E-04 - 7.2355658370E-04 -4.5839948962E-04 -3.1631926894E-04 - -2.3833082399E-04 -1.4228122763E-04 -4.4666526474E-04 - 3.7299276768E-04 4.0538603116E-04 -2.7690877227E-05 - -6.4569243847E-05 3.8275532625E-04 -5.6777340069E-05 - -6.9869904226E-04 -6.0113796812E-04 2.6313012588E-04 - 1.4206158707E-04 1.3384725450E-04 3.8801613795E-04 - 5.5183302922E-04 -4.7367665638E-04 1.4120024055E-04 - -4.3998448094E-04 -1.5046508502E-05 -6.2320039975E-04 - 5.6763021836E-05 8.9306008827E-06 -3.1022670489E-04 - 8.8966422184E-06 -4.8414938314E-04 4.4651370088E-04 - 4.5496150508E-04 -4.0520847219E-05 3.8534366697E-04 - 6.8647674490E-04 3.3865640654E-04 -5.1201904882E-05 - -7.9240240818E-04 5.8055869571E-04 -3.0700044678E-04 - -2.6769159960E-05 -8.4196029706E-04 -5.3070005344E-05 - -4.1560566153E-04 6.0074674573E-04 -2.4096741820E-05 - -2.4464499284E-04 8.3046762283E-06 -4.3162561945E-04 - 2.3828975580E-04 1.7668699214E-04 5.0613011272E-04 - -3.9350341718E-04 -3.6453407051E-05 -3.5791422650E-04 -:F: - -3.8178607711E-03 6.6673142068E-03 1.8791341847E-03 - -5.1867827308E-04 -2.9468279936E-03 2.3028950630E-03 - 1.1582512280E-02 -3.2707122551E-03 -3.6662966038E-03 - 1.0159029365E-02 -1.9153614492E-03 -1.2542768636E-03 - 1.1621887415E-02 1.9407079610E-03 1.8270453699E-03 - 1.5126311251E-02 5.3566075554E-03 7.2441024751E-04 - 9.8285375653E-03 -5.2551674955E-03 1.0424612745E-04 - 1.4366123208E-02 1.0782583289E-03 2.6916448414E-04 - 1.4361526448E-02 -1.7332742318E-03 -1.1352229109E-03 - -3.2844546374E-03 3.5392940415E-03 -4.2336067460E-03 - 7.3087539998E-03 -2.9452017461E-03 -1.5778707978E-03 - -1.1633221492E-02 -4.6162724731E-03 5.0021850657E-03 - -1.0453373810E-02 1.9089271399E-03 2.8562058418E-03 - -1.1077124281E-02 -1.3499412290E-03 -2.2389660660E-04 - -1.4990999082E-02 5.1512961688E-03 -3.6960008533E-03 - -1.0554193641E-02 -4.9030879647E-03 1.4735213419E-03 - -1.3976258943E-02 3.3247532349E-03 1.1692348809E-03 - -1.4796217926E-02 -2.8248964926E-04 -2.1755822835E-03 - 5.4895338109E-03 -4.2056275793E-04 1.6143909545E-02 - -4.7418324875E-03 6.7174060807E-04 -1.5789198487E-02 -:LATVEC_SCALE: 1.8897235286E+01 1.8897235286E+01 1.8897232612E+01 -:STRIO: - -7.2232193751E-01 9.9985896045E-02 -1.4924905353E-01 - 9.9985896045E-02 -7.3673748746E-01 2.6289501392E-02 - -1.4924905353E-01 2.6289501392E-02 -4.9209854815E-01 -:STRESS: - 4.8481715913E+00 -1.6296171037E-02 -8.0091932956E-03 - -1.6296171037E-02 5.4799753042E+00 2.0547083753E-02 - -8.0091932956E-03 2.0547083753E-02 5.8257439764E+00 -:PRESIO: 6.5038599104E-01 -:PRES: -5.3846302906E+00 -:PRESIG: 6.9142782570E-01 -:MIND: -Al - Al: 5.9094681381E+00 -C - C: 1.9766197544E+01 -Al - C: 6.2152626911E+00 diff --git a/tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.refout b/tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.refout deleted file mode 100644 index caaad197..00000000 --- a/tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.refout +++ /dev/null @@ -1,600 +0,0 @@ -*************************************************************************** -* SPARC (version June 24, 2024) * -* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * -* Distributed under GNU General Public License 3 (GPL) * -* Start time: Sun Aug 11 19:39:34 2024 * -*************************************************************************** - Input parameters -*************************************************************************** -LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 -LATVEC: -1.000000000000000 0.000000000000000 0.000000000000000 -0.000000000000000 1.000000000000000 0.000000000000000 -0.000000000000000 0.000000000000000 1.000000000000000 -FD_GRID: 63 63 63 -FD_ORDER: 12 -BC: P P P -KPOINT_GRID: 1 1 1 -KPOINT_SHIFT: 0 0 0 -SPIN_TYP: 0 -ELEC_TEMP_TYPE: Fermi-Dirac -ELEC_TEMP: 2400 -EXCHANGE_CORRELATION: GGA_PBE -NSTATES: 72 -CHEB_DEGREE: 25 -CHEFSI_BOUND_FLAG: 0 -CALC_STRESS: 1 -TWTIME: 1E+09 -MD_FLAG: 1 -MD_METHOD: NPT_NP -MD_TIMESTEP: 1 -MD_NSTEP: 10 -ION_VEL_DSTR: 2 -ION_VEL_DSTR_RAND: 0 -ION_TEMP: 2400 -NPT_SCALE_VECS: 1 2 3 -NPT_SCALE_CONSTRAINTS: 12 -NPT_NP_QMASS: 20000 -NPT_NP_BMASS: 400 -TARGET_PRESSURE: 0.1 GPa -MAXIT_SCF: 100 -MINIT_SCF: 2 -MAXIT_POISSON: 3000 -TOL_SCF: 1.00E-06 -POISSON_SOLVER: AAR -TOL_POISSON: 1.00E-08 -TOL_LANCZOS: 1.00E-02 -TOL_PSEUDOCHARGE: 1.00E-09 -MIXING_VARIABLE: density -MIXING_PRECOND: kerker -TOL_PRECOND: 9.00E-05 -PRECOND_KERKER_KTF: 1 -PRECOND_KERKER_THRESH: 0 -MIXING_PARAMETER: 1 -MIXING_HISTORY: 7 -PULAY_FREQUENCY: 1 -PULAY_RESTART: 0 -REFERENCE_CUTOFF: 0.5 -RHO_TRIGGER: 4 -NUM_CHEFSI: 1 -FIX_RAND: 0 -VERBOSITY: 1 -PRINT_FORCES: 1 -PRINT_ATOMS: 1 -PRINT_EIGEN: 0 -PRINT_DENSITY: 0 -PRINT_MDOUT: 1 -PRINT_VELS: 1 -PRINT_RESTART: 1 -PRINT_RESTART_FQ: 1 -PRINT_ENERGY_DENSITY: 0 -OUTPUT_FILE: Al18C2_NPTNP_aeqb_c/temp_run/Al18C2_NPTNP_aeqb_c -*************************************************************************** - Cell -*************************************************************************** -Lattice vectors (Bohr): -18.897259886000001 0.000000000000000 0.000000000000000 -0.000000000000000 18.897259886000001 0.000000000000000 -0.000000000000000 0.000000000000000 18.897259886000001 -Volume: 6.7483330373E+03 (Bohr^3) -Density: 7.5528236408E-02 (amu/Bohr^3), 8.4635982984E-01 (g/cc) -*************************************************************************** - Parallelization -*************************************************************************** -NP_SPIN_PARAL: 1 -NP_KPOINT_PARAL: 1 -NP_BAND_PARAL: 24 -NP_DOMAIN_PARAL: 1 1 2 -NP_DOMAIN_PHI_PARAL: 3 4 4 -EIG_SERIAL_MAXNS: 1500 -*************************************************************************** - Initialization -*************************************************************************** -Number of processors : 48 -Mesh spacing : 0.299957 (Bohr) -Number of symmetry adapted k-points: 1 -Output printed to : Al18C2_NPTNP_aeqb_c/temp_run/Al18C2_NPTNP_aeqb_c.out -MD output printed to : Al18C2_NPTNP_aeqb_c/temp_run/Al18C2_NPTNP_aeqb_c.aimd -Total number of atom types : 2 -Total number of atoms : 20 -Total number of electrons : 62 -Atom type 1 (valence electrons) : Al 3 -Pseudopotential : ../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 -Atomic mass : 26.9815385 -Pseudocharge radii of atom type 1 : 7.80 7.80 7.80 (x, y, z dir) -Number of atoms of type 1 : 18 -Atom type 2 (valence electrons) : C 4 -Pseudopotential : ../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 -Atomic mass : 12.011 -Pseudocharge radii of atom type 2 : 7.80 7.80 7.80 (x, y, z dir) -Number of atoms of type 2 : 2 -Estimated total memory usage : 1.02 GB -Estimated memory per processor : 21.69 MB -=================================================================== - Self Consistent Field (SCF#1) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6060398800E+00 2.032E-01 1.384 -2 -2.6385255256E+00 5.766E-01 0.401 -3 -2.6180007012E+00 2.684E-01 0.390 -4 -2.6166095995E+00 1.891E-01 0.394 -5 -2.6164056057E+00 1.450E-01 0.392 -6 -2.6162791012E+00 1.522E-01 0.389 -7 -2.6157673615E+00 3.496E-02 0.384 -8 -2.6157655368E+00 2.996E-02 0.383 -9 -2.6157607749E+00 2.175E-02 0.383 -10 -2.6157558875E+00 1.253E-02 0.385 -11 -2.6157532532E+00 3.931E-03 0.378 -12 -2.6157532799E+00 7.970E-04 0.376 -13 -2.6157534695E+00 3.356E-04 0.369 -14 -2.6157535146E+00 2.070E-04 0.368 -15 -2.6157535323E+00 7.974E-05 0.363 -16 -2.6157535313E+00 4.894E-05 0.362 -17 -2.6157535325E+00 1.754E-05 0.360 -18 -2.6157535330E+00 1.065E-05 0.355 -19 -2.6157535351E+00 4.042E-06 0.351 -20 -2.6157535340E+00 2.649E-06 0.347 -21 -2.6157535350E+00 1.751E-06 0.347 -22 -2.6157535351E+00 1.237E-06 0.343 -23 -2.6157535344E+00 8.528E-07 0.338 -Total number of SCF: 23 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6157535344E+00 (Ha/atom) -Total free energy : -5.2315070688E+01 (Ha) -Band structure energy : -9.0973588728E+00 (Ha) -Exchange correlation energy : -2.0462168209E+01 (Ha) -Self and correction energy : -7.6944567485E+01 (Ha) --Entropy*kb*T : -1.4407939960E-01 (Ha) -Fermi level : -2.8356711115E-02 (Ha) -RMS force : 1.0668208541E-02 (Ha/Bohr) -Maximum force : 1.3289479843E-02 (Ha/Bohr) -Time for force calculation : 0.046 (sec) -Pressure : -5.4524749130E+00 (GPa) -Maximum stress : 5.8252447875E+00 (GPa) -Time for stress calculation : 0.080 (sec) -MD step time : 9.862 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972593404266 18.8972593404266 18.897259283577 -CHEB_DEGREE: 25 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299956 (Bohr) -Mesh spacing in y-direction : 0.299956 (Bohr) -Mesh spacing in z direction : 0.299956 (Bohr) -=================================================================== - Self Consistent Field (SCF#2) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6159704471E+00 3.763E-02 0.408 -2 -2.6165209011E+00 1.862E-01 0.388 -3 -2.6158145514E+00 5.328E-02 0.388 -4 -2.6159506864E+00 9.243E-02 0.385 -5 -2.6157573878E+00 3.521E-03 0.382 -6 -2.6157563249E+00 2.127E-03 0.380 -7 -2.6157563913E+00 9.785E-04 0.378 -8 -2.6157566724E+00 5.295E-04 0.377 -9 -2.6157568898E+00 3.374E-04 0.375 -10 -2.6157570259E+00 1.558E-04 0.371 -11 -2.6157570763E+00 7.824E-05 0.363 -12 -2.6157570829E+00 6.384E-05 0.359 -13 -2.6157570839E+00 9.330E-05 0.355 -14 -2.6157570845E+00 1.821E-05 0.358 -15 -2.6157570851E+00 6.222E-06 0.364 -16 -2.6157570855E+00 3.157E-06 0.353 -17 -2.6157570853E+00 1.850E-06 0.345 -18 -2.6157570882E+00 9.951E-07 0.344 -Total number of SCF: 18 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6157570882E+00 (Ha/atom) -Total free energy : -5.2315141763E+01 (Ha) -Band structure energy : -9.0981181373E+00 (Ha) -Exchange correlation energy : -2.0462504684E+01 (Ha) -Self and correction energy : -7.6944575395E+01 (Ha) --Entropy*kb*T : -1.4398161428E-01 (Ha) -Fermi level : -2.8380080632E-02 (Ha) -RMS force : 1.0679385817E-02 (Ha/Bohr) -Maximum force : 1.3518515076E-02 (Ha/Bohr) -Time for force calculation : 0.043 (sec) -Pressure : -5.4509519448E+00 (GPa) -Maximum stress : 5.8275378001E+00 (GPa) -Time for stress calculation : 0.072 (sec) -MD step time : 6.908 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972582496052 18.8972582496052 18.897258078472 -CHEB_DEGREE: 25 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299956 (Bohr) -Mesh spacing in y-direction : 0.299956 (Bohr) -Mesh spacing in z direction : 0.299956 (Bohr) -=================================================================== - Self Consistent Field (SCF#3) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6159957723E+00 3.809E-02 0.412 -2 -2.6165611840E+00 1.880E-01 0.389 -3 -2.6158387001E+00 5.421E-02 0.387 -4 -2.6159769618E+00 9.333E-02 0.386 -5 -2.6157798634E+00 3.577E-03 0.384 -6 -2.6157787426E+00 2.226E-03 0.379 -7 -2.6157787896E+00 1.003E-03 0.380 -8 -2.6157790810E+00 5.388E-04 0.376 -9 -2.6157793031E+00 3.593E-04 0.373 -10 -2.6157794520E+00 1.602E-04 0.371 -11 -2.6157795064E+00 8.126E-05 0.361 -12 -2.6157795139E+00 5.179E-05 0.360 -13 -2.6157795146E+00 6.505E-05 0.353 -14 -2.6157795150E+00 1.964E-05 0.355 -15 -2.6157795156E+00 6.279E-06 0.355 -16 -2.6157795159E+00 3.152E-06 0.349 -17 -2.6157795167E+00 2.037E-06 0.347 -18 -2.6157795186E+00 1.123E-06 0.346 -19 -2.6157795175E+00 3.957E-07 0.338 -Total number of SCF: 19 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6157795175E+00 (Ha/atom) -Total free energy : -5.2315590350E+01 (Ha) -Band structure energy : -9.0991150178E+00 (Ha) -Exchange correlation energy : -2.0463500637E+01 (Ha) -Self and correction energy : -7.6944599429E+01 (Ha) --Entropy*kb*T : -1.4382202775E-01 (Ha) -Fermi level : -2.8414873758E-02 (Ha) -RMS force : 1.0736301309E-02 (Ha/Bohr) -Maximum force : 1.3783759549E-02 (Ha/Bohr) -Time for force calculation : 0.043 (sec) -Pressure : -5.4473827622E+00 (GPa) -Maximum stress : 5.8287806108E+00 (GPa) -Time for stress calculation : 0.072 (sec) -MD step time : 7.238 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972566139792 18.8972566139792 18.8972562703772 -CHEB_DEGREE: 25 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299956 (Bohr) -Mesh spacing in y-direction : 0.299956 (Bohr) -Mesh spacing in z direction : 0.299956 (Bohr) -=================================================================== - Self Consistent Field (SCF#4) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6157725216E+00 4.108E-03 0.395 -2 -2.6158299089E+00 1.619E-02 0.378 -3 -2.6158242487E+00 4.115E-03 0.374 -4 -2.6158251591E+00 8.065E-03 0.373 -5 -2.6158240562E+00 1.802E-04 0.369 -6 -2.6158240574E+00 6.609E-05 0.364 -7 -2.6158240585E+00 5.211E-05 0.376 -8 -2.6158240589E+00 1.403E-05 0.363 -9 -2.6158240595E+00 6.583E-06 0.358 -10 -2.6158240593E+00 4.590E-06 0.357 -11 -2.6158240590E+00 1.478E-06 0.351 -12 -2.6158240574E+00 7.139E-07 0.351 -Total number of SCF: 12 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6158240574E+00 (Ha/atom) -Total free energy : -5.2316481148E+01 (Ha) -Band structure energy : -9.1004151949E+00 (Ha) -Exchange correlation energy : -2.0465148601E+01 (Ha) -Self and correction energy : -7.6944637813E+01 (Ha) --Entropy*kb*T : -1.4360384818E-01 (Ha) -Fermi level : -2.8465463458E-02 (Ha) -RMS force : 1.0847088673E-02 (Ha/Bohr) -Maximum force : 1.4080185021E-02 (Ha/Bohr) -Time for force calculation : 0.042 (sec) -Pressure : -5.4423382977E+00 (GPa) -Maximum stress : 5.8295335006E+00 (GPa) -Time for stress calculation : 0.072 (sec) -MD step time : 4.632 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972544337492 18.8972544337492 18.897253858544 -CHEB_DEGREE: 25 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299956 (Bohr) -Mesh spacing in y-direction : 0.299956 (Bohr) -Mesh spacing in z direction : 0.299956 (Bohr) -=================================================================== - Self Consistent Field (SCF#5) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6158312552E+00 3.508E-03 0.383 -2 -2.6158866293E+00 5.433E-03 0.367 -3 -2.6158898553E+00 1.426E-02 0.372 -4 -2.6158865859E+00 1.472E-03 0.366 -5 -2.6158865408E+00 4.469E-04 0.362 -6 -2.6158865388E+00 7.080E-05 0.360 -7 -2.6158865387E+00 3.703E-05 0.359 -8 -2.6158865392E+00 2.045E-05 0.358 -9 -2.6158865399E+00 1.206E-05 0.362 -10 -2.6158865396E+00 6.123E-06 0.353 -11 -2.6158865406E+00 2.288E-06 0.349 -12 -2.6158865390E+00 1.959E-06 0.342 -13 -2.6158865399E+00 4.493E-06 0.335 -14 -2.6158865404E+00 1.319E-06 0.338 -15 -2.6158865416E+00 3.414E-07 0.336 -Total number of SCF: 15 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6158865416E+00 (Ha/atom) -Total free energy : -5.2317730833E+01 (Ha) -Band structure energy : -9.1019340715E+00 (Ha) -Exchange correlation energy : -2.0467459405E+01 (Ha) -Self and correction energy : -7.6944689700E+01 (Ha) --Entropy*kb*T : -1.4332325316E-01 (Ha) -Fermi level : -2.8529515478E-02 (Ha) -RMS force : 1.1007660100E-02 (Ha/Bohr) -Maximum force : 1.4403603031E-02 (Ha/Bohr) -Time for force calculation : 0.043 (sec) -Pressure : -5.4357238338E+00 (GPa) -Maximum stress : 5.8296993850E+00 (GPa) -Time for stress calculation : 0.072 (sec) -MD step time : 5.568 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.897251708413 18.897251708413 18.8972508412711 -CHEB_DEGREE: 25 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299956 (Bohr) -Mesh spacing in y-direction : 0.299956 (Bohr) -Mesh spacing in z direction : 0.299956 (Bohr) -=================================================================== - Self Consistent Field (SCF#6) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6159145924E+00 3.449E-03 0.385 -2 -2.6159679095E+00 3.089E-03 0.369 -3 -2.6159725927E+00 1.612E-02 0.372 -4 -2.6159682540E+00 2.007E-03 0.400 -5 -2.6159681669E+00 3.913E-04 0.361 -6 -2.6159681660E+00 6.785E-05 0.361 -7 -2.6159681659E+00 3.704E-05 0.357 -8 -2.6159681671E+00 1.922E-05 0.359 -9 -2.6159681669E+00 1.020E-05 0.356 -10 -2.6159681671E+00 5.073E-06 0.353 -11 -2.6159681679E+00 1.983E-06 0.350 -12 -2.6159681658E+00 1.487E-06 0.353 -13 -2.6159681667E+00 3.023E-06 0.335 -14 -2.6159681688E+00 1.609E-06 0.336 -15 -2.6159681687E+00 3.494E-07 0.336 -Total number of SCF: 15 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6159681687E+00 (Ha/atom) -Total free energy : -5.2319363374E+01 (Ha) -Band structure energy : -9.1037569159E+00 (Ha) -Exchange correlation energy : -2.0470425703E+01 (Ha) -Self and correction energy : -7.6944752292E+01 (Ha) --Entropy*kb*T : -1.4297613582E-01 (Ha) -Fermi level : -2.8608044373E-02 (Ha) -RMS force : 1.1204666621E-02 (Ha/Bohr) -Maximum force : 1.4752878886E-02 (Ha/Bohr) -Time for force calculation : 0.043 (sec) -Pressure : -5.4277765962E+00 (GPa) -Maximum stress : 5.8293891818E+00 (GPa) -Time for stress calculation : 0.072 (sec) -MD step time : 5.609 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972484361565 18.8972484361565 18.8972472152472 -CHEB_DEGREE: 25 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299956 (Bohr) -Mesh spacing in y-direction : 0.299956 (Bohr) -Mesh spacing in z direction : 0.299956 (Bohr) -=================================================================== - Self Consistent Field (SCF#7) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6160209703E+00 3.442E-03 0.380 -2 -2.6160731762E+00 2.969E-03 0.375 -3 -2.6160760519E+00 1.079E-02 0.379 -4 -2.6160734409E+00 1.865E-03 0.486 -5 -2.6160733965E+00 7.370E-04 0.364 -6 -2.6160733889E+00 6.512E-05 0.360 -7 -2.6160733879E+00 3.451E-05 0.361 -8 -2.6160733889E+00 1.960E-05 0.357 -9 -2.6160733897E+00 1.120E-05 0.356 -10 -2.6160733891E+00 5.519E-06 0.354 -11 -2.6160733901E+00 2.557E-06 0.349 -12 -2.6160733895E+00 1.109E-06 0.353 -13 -2.6160733899E+00 1.516E-06 0.340 -14 -2.6160733904E+00 3.931E-07 0.339 -Total number of SCF: 14 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6160733904E+00 (Ha/atom) -Total free energy : -5.2321467807E+01 (Ha) -Band structure energy : -9.1060343409E+00 (Ha) -Exchange correlation energy : -2.0474034765E+01 (Ha) -Self and correction energy : -7.6944820593E+01 (Ha) --Entropy*kb*T : -1.4255967247E-01 (Ha) -Fermi level : -2.8701822006E-02 (Ha) -RMS force : 1.1428249933E-02 (Ha/Bohr) -Maximum force : 1.5124289597E-02 (Ha/Bohr) -Time for force calculation : 0.043 (sec) -Pressure : -5.4186930042E+00 (GPa) -Maximum stress : 5.8287290003E+00 (GPa) -Time for stress calculation : 0.072 (sec) -MD step time : 5.377 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972446131766 18.8972446131766 18.8972429748038 -CHEB_DEGREE: 25 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299956 (Bohr) -Mesh spacing in y-direction : 0.299956 (Bohr) -Mesh spacing in z direction : 0.299956 (Bohr) -=================================================================== - Self Consistent Field (SCF#8) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6161520566E+00 3.433E-03 0.380 -2 -2.6162035360E+00 4.308E-03 0.370 -3 -2.6162063445E+00 1.212E-02 0.372 -4 -2.6162043283E+00 6.175E-03 0.379 -5 -2.6162035766E+00 2.496E-04 0.361 -6 -2.6162035788E+00 6.041E-05 0.359 -7 -2.6162035791E+00 4.484E-05 0.358 -8 -2.6162035803E+00 1.946E-05 0.356 -9 -2.6162035805E+00 9.965E-06 0.354 -10 -2.6162035806E+00 5.028E-06 0.355 -11 -2.6162035812E+00 3.105E-06 0.349 -12 -2.6162035799E+00 9.838E-07 0.343 -Total number of SCF: 12 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6162035799E+00 (Ha/atom) -Total free energy : -5.2324071597E+01 (Ha) -Band structure energy : -9.1088709813E+00 (Ha) -Exchange correlation energy : -2.0478264321E+01 (Ha) -Self and correction energy : -7.6944887498E+01 (Ha) --Entropy*kb*T : -1.4207737371E-01 (Ha) -Fermi level : -2.8810296147E-02 (Ha) -RMS force : 1.1670785382E-02 (Ha/Bohr) -Maximum force : 1.5514501902E-02 (Ha/Bohr) -Time for force calculation : 0.042 (sec) -Pressure : -5.4085038724E+00 (GPa) -Maximum stress : 5.8277968194E+00 (GPa) -Time for stress calculation : 0.072 (sec) -MD step time : 4.557 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972402329924 18.8972402329924 18.8972381111291 -CHEB_DEGREE: 25 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299956 (Bohr) -Mesh spacing in y-direction : 0.299956 (Bohr) -Mesh spacing in z direction : 0.299956 (Bohr) -=================================================================== - Self Consistent Field (SCF#9) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6163042908E+00 3.417E-03 0.381 -2 -2.6163549540E+00 3.778E-03 0.375 -3 -2.6163574655E+00 1.043E-02 0.413 -4 -2.6163552902E+00 3.718E-03 0.366 -5 -2.6163550564E+00 3.382E-04 0.366 -6 -2.6163550556E+00 6.442E-05 0.367 -7 -2.6163550555E+00 4.137E-05 0.359 -8 -2.6163550563E+00 2.046E-05 0.358 -9 -2.6163550567E+00 1.232E-05 0.356 -10 -2.6163550562E+00 5.365E-06 0.360 -11 -2.6163550580E+00 2.467E-06 0.349 -12 -2.6163550566E+00 9.767E-07 0.343 -Total number of SCF: 12 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6163550566E+00 (Ha/atom) -Total free energy : -5.2327101131E+01 (Ha) -Band structure energy : -9.1122352080E+00 (Ha) -Exchange correlation energy : -2.0483095514E+01 (Ha) -Self and correction energy : -7.6944946044E+01 (Ha) --Entropy*kb*T : -1.4153540997E-01 (Ha) -Fermi level : -2.8931283116E-02 (Ha) -RMS force : 1.1925854786E-02 (Ha/Bohr) -Maximum force : 1.6262496453E-02 (Ha/Bohr) -Time for force calculation : 0.042 (sec) -Pressure : -5.3972155919E+00 (GPa) -Maximum stress : 5.8268077883E+00 (GPa) -Time for stress calculation : 0.072 (sec) -MD step time : 4.620 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 18.8972352858125 18.8972352858125 18.8972326115099 -CHEB_DEGREE: 25 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299956 (Bohr) -Mesh spacing in y-direction : 0.299956 (Bohr) -Mesh spacing in z direction : 0.299956 (Bohr) -=================================================================== - Self Consistent Field (SCF#10) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6164730832E+00 3.385E-03 0.382 -2 -2.6165231200E+00 1.976E-03 0.370 -3 -2.6165268367E+00 1.371E-02 0.372 -4 -2.6165235682E+00 1.835E-03 0.366 -5 -2.6165235003E+00 5.296E-04 0.363 -6 -2.6165234972E+00 6.926E-05 0.363 -7 -2.6165234967E+00 3.221E-05 0.356 -8 -2.6165234982E+00 1.400E-05 0.358 -9 -2.6165234986E+00 8.639E-06 0.358 -10 -2.6165234988E+00 4.483E-06 0.351 -11 -2.6165234987E+00 2.191E-06 0.350 -12 -2.6165234980E+00 1.301E-06 0.342 -13 -2.6165234973E+00 1.066E-06 0.335 -14 -2.6165234984E+00 9.367E-07 0.339 -Total number of SCF: 14 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6165234984E+00 (Ha/atom) -Total free energy : -5.2330469968E+01 (Ha) -Band structure energy : -9.1160664236E+00 (Ha) -Exchange correlation energy : -2.0488525358E+01 (Ha) -Self and correction energy : -7.6944990650E+01 (Ha) --Entropy*kb*T : -1.4093509905E-01 (Ha) -Fermi level : -2.9062507360E-02 (Ha) -RMS force : 1.2188418965E-02 (Ha/Bohr) -Maximum force : 1.7056895084E-02 (Ha/Bohr) -Time for force calculation : 0.043 (sec) -Pressure : -5.3846302906E+00 (GPa) -Maximum stress : 5.8257439764E+00 (GPa) -Time for stress calculation : 0.072 (sec) -MD step time : 5.231 (sec) -*************************************************************************** - Timing info -*************************************************************************** -Total walltime : 59.643 sec -___________________________________________________________________________ - -*************************************************************************** -* Material Physics & Mechanics Group, Georgia Tech * -* PI: Phanish Suryanarayana * -* List of contributors: See the documentation * -* Citation: See README.md or the documentation for details * -* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * -* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * -*************************************************************************** - diff --git a/tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.inpt b/tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.inpt similarity index 92% rename from tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.inpt rename to tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.inpt index abb8f541..014f964e 100644 --- a/tests/Al18C2_NPTNP_aeqb_c/high_accuracy/Al18C2_NPTNP_aeqb_c.inpt +++ b/tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.inpt @@ -27,12 +27,14 @@ MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whicheve #TWTIME: 1400 RESTART_FLAG: 0 # 1 = restart MD from .restart file if present, 0 = start new #ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) -TARGET_PRESSURE: 0.1 GPa +EXTERNAL_PRESSURE: 0.1 GPa NPT_NP_QMASS: 20000 -NPT_NP_BMASS: 400 +NPT_NP_BMASS: 40 +#NPT_NP_ANGLES: 0 +NPT_SCALE_VECS: 1 2 NPT_SCALE_CONSTRAINTS: 12 -NSTATES: 72 +NSTATES: 80 # outputs # CALC_PRES: 1 diff --git a/tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.ion b/tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.ion similarity index 100% rename from tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.ion rename to tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.ion diff --git a/tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.refaimd b/tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.refaimd new file mode 100644 index 00000000..f7983da2 --- /dev/null +++ b/tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.refaimd @@ -0,0 +1,1168 @@ +:Description: + +:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr +:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu + where atu is the atomic unit of time, hbar/Ha +:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr +:Desc_MDTM: MD time. Unit=second +:Desc_TEL: Electronic temperature. Unit=Kelvin +:Desc_TIO: Ionic temperature. Unit=Kelvin +:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom +:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom +:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom + where N = number of particles, k = Boltzmann constant +:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom +:Desc_UEN: Internal energy. Unit=Ha/atom +:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom +:Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree +:Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 +:Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 +:Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during NPT_NP ensemble (has same magnitude as initial LatVec). Unit = Bohr +:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha +:Desc_SNOSE[0]: Position variable of the thermostat +:Desc_SNOSE[1]: Velocity variable of the thermostat +:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa +:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa +:Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa +:Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa +:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa + where N = number of particles, k = Boltzmann constant, V = volume +:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr + + + + +:MDSTEP: 1 +:MDTM: 95.24 +:TWIST: 0 +:TEL: 2400 +:TIO: 2400.34102745402 +:TEN: -2.6048830082E+00 +:KEN: 1.0832034504E-02 +:KENIG: 1.1402141583E-02 +:FEN: -2.6157150427E+00 +:UEN: -2.6085105497E+00 +:TSEN: -7.2044930425E-03 +:NPT_NP_HAMIL: 3.0845115980E-05 +:SNOSE[0]: 1.0000000000E+00 +:SNOSE[1]: 0.0000000000E+00 +:R: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 6.2990803296E+00 + 0.0000000000E+00 0.0000000000E+00 1.2598160659E+01 + 0.0000000000E+00 6.2990803296E+00 0.0000000000E+00 + 0.0000000000E+00 6.2990803296E+00 6.2990803296E+00 + 0.0000000000E+00 6.2990803296E+00 1.2598160659E+01 + 0.0000000000E+00 1.2598160659E+01 0.0000000000E+00 + 0.0000000000E+00 1.2598160659E+01 6.2990803296E+00 + 0.0000000000E+00 1.2598160659E+01 1.2598160659E+01 + 6.2990803296E+00 0.0000000000E+00 0.0000000000E+00 + 6.2990803296E+00 0.0000000000E+00 6.2990803296E+00 + 6.2990803296E+00 0.0000000000E+00 1.2598160659E+01 + 6.2990803296E+00 6.2990803296E+00 0.0000000000E+00 + 6.2990803296E+00 6.2990803296E+00 6.2990803296E+00 + 6.2990803296E+00 6.2990803296E+00 1.2598160659E+01 + 6.2990803296E+00 1.2598160659E+01 0.0000000000E+00 + 6.2990803296E+00 1.2598160659E+01 6.2990803296E+00 + 6.2990803296E+00 1.2598160659E+01 1.2598160659E+01 + 1.2598160659E+01 0.0000000000E+00 0.0000000000E+00 + 1.2598160659E+01 0.0000000000E+00 6.2990803296E+00 +:V: + -6.7508383715E-06 6.8757511443E-04 4.3936260098E-04 + 3.7355668107E-05 -1.5727035196E-04 5.1719530241E-04 + 6.4986381738E-04 -4.5410617479E-04 -3.0784983002E-04 + -3.2394420293E-04 -1.3629699967E-04 -4.4900402391E-04 + 2.9184533820E-04 4.0511690293E-04 -3.3972671596E-05 + -1.6699314265E-04 3.6969183614E-04 -5.9863047141E-05 + -7.8895518395E-04 -5.9299532023E-04 2.6594886314E-04 + 4.8087383748E-05 1.3106944282E-04 3.9308979235E-04 + 4.6023591418E-04 -4.7427996968E-04 1.4680549611E-04 + -4.4621371268E-04 -2.7196365396E-05 -6.1810882351E-04 + 2.1175066025E-05 1.9314808568E-05 -3.0796047636E-04 + 9.2718370724E-05 -4.7512761917E-04 4.3477901232E-04 + 5.4429990961E-04 -4.6900723938E-05 3.8053215623E-04 + 7.8083614347E-04 3.4893054874E-04 -5.1048609500E-05 + -7.0230041644E-04 5.7124857392E-04 -2.9842620575E-04 + 5.5677155225E-05 -8.3790479758E-04 -5.9249898262E-05 + -3.2642487704E-04 5.9659761857E-04 -2.8120762688E-05 + -1.4748612137E-04 9.7054910337E-06 -4.3002558645E-04 + 1.9870161127E-04 1.8287978550E-04 2.9481470865E-04 + -3.6274799784E-04 -4.1742852422E-05 -1.4673925341E-04 +:F: + -3.1866258108E-03 1.5952726842E-07 3.2888275626E-04 + -3.1868127958E-03 1.5418399784E-07 -3.2888049918E-04 + 1.1727460436E-02 1.3912327029E-07 -1.0726009018E-07 + 1.2514180763E-02 -2.4252665419E-04 1.2603858707E-04 + 1.2514272584E-02 -2.4256390302E-04 -1.2589472614E-04 + 1.3273769749E-02 -5.5087819798E-05 -1.6128895991E-07 + 1.2514142618E-02 2.4237746676E-04 1.2603122773E-04 + 1.2514199178E-02 2.4240805985E-04 -1.2587687376E-04 + 1.3273686084E-02 5.4941100339E-05 -1.6347784961E-07 + 3.1913650751E-03 1.5447172049E-07 3.2899522468E-04 + 3.1910364899E-03 1.5004979420E-07 -3.2899350984E-04 + -1.1727660922E-02 1.4300665679E-07 -1.0852318157E-07 + -1.2514201252E-02 -2.4259249157E-04 1.2599954137E-04 + -1.2514294787E-02 -2.4261183806E-04 -1.2586138282E-04 + -1.3273733053E-02 -5.5067188352E-05 -1.5975853554E-07 + -1.2514188952E-02 2.4243071644E-04 1.2599840023E-04 + -1.2514238897E-02 2.4246423938E-04 -1.2583581035E-04 + -1.3273659686E-02 5.4914938505E-05 -1.6579539919E-07 + -4.5835623201E-06 1.6821591053E-08 1.1883442045E-02 + -4.1132571337E-06 -3.8105828341E-09 -1.1883178877E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483330373E+03 +:LATVEC_SCALE: + 1.8897259886E+01 1.8897259886E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0617480897E-01 -7.6076991542E-02 1.3809311446E-01 + -7.6076991542E-02 7.2214981572E-01 -2.9244330384E-02 + 1.3809311446E-01 -2.9244330384E-02 4.6067199357E-01 +:STRESS: + 4.9507440804E+00 -1.9741297828E-08 5.9460670801E-07 + -1.9741297828E-08 5.5272928418E+00 -8.2407346628E-08 + 5.9460670801E-07 -8.2407346628E-08 5.7978462213E+00 +:CONSTRESS: + 2.8053078172E-01 -7.4793767904E-02 1.3794634300E-01 + -7.4793767904E-02 -2.8053078172E-01 -2.9489547668E-02 + 1.3794634300E-01 -2.9489547668E-02 -5.4380697089E+00 +:TOTSTRESS: + -4.5251000532E+00 -1.2832038969E-03 1.4617685227E-04 + -1.2832038969E-03 -4.5246122444E+00 2.4529969145E-04 + 1.4617685227E-04 2.4529969145E-04 1.0089548111E-01 +:PRESIO: 6.2966553942E-01 +:PRES: -5.4252943812E+00 +:CONPRES: -1.8126899030E+00 +:TOTPRES: -2.9829389388E+00 +:PRESIG: 6.6280583097E-01 +:MIND: +Al - Al: 6.2990803296E+00 +C - C: 6.2990803296E+00 +Al - C: 6.2990803296E+00 + + +:MDSTEP: 2 +:MDTM: 73.43 +:TWIST: 0 +:TEL: 2400 +:TIO: 2403.19561781406 +:TEN: -2.6048828988E+00 +:KEN: 1.0844916432E-02 +:KENIG: 1.1415701508E-02 +:FEN: -2.6157278152E+00 +:UEN: -2.6085282435E+00 +:TSEN: -7.1995717476E-03 +:NPT_NP_HAMIL: 3.5153989397E-05 +:SNOSE[0]: 1.0000036967E+00 +:SNOSE[1]: 4.3955572927E-07 +:R: + 1.8896920730E+01 2.8425242661E-02 1.8169533916E-02 + 1.4889621336E-03 1.8890753428E+01 6.3204561400E+00 + 2.7069965000E-02 1.8878481853E+01 1.2585433746E+01 + 1.8884080341E+01 6.2934398551E+00 1.8878699667E+01 + 1.2282690892E-02 6.3158226018E+00 6.2976736679E+00 + 1.8890582098E+01 6.3143613413E+00 1.2595685840E+01 + 1.8864856188E+01 1.2573646546E+01 1.0996860646E-02 + 2.2054221515E-03 1.2603580316E+01 6.3153289844E+00 + 1.9257368383E-02 1.2578551135E+01 1.2604229786E+01 + 6.2806871616E+00 1.8896130854E+01 1.8871712182E+01 + 6.3000096093E+00 7.9850164437E-04 6.2863431280E+00 + 6.3027080968E+00 1.8877612799E+01 1.2616134986E+01 + 6.3213633929E+00 6.2971356110E+00 1.5733882038E-02 + 6.3311421035E+00 6.3134997848E+00 6.2969677271E+00 + 6.2698141351E+00 6.3226939565E+00 1.2585823330E+01 + 6.3011630998E+00 1.2563521674E+01 1.8894812608E+01 + 6.2853665093E+00 1.2622825850E+01 6.2979155944E+00 + 6.2927508731E+00 1.2598559716E+01 1.2580382841E+01 + 1.2606371926E+01 7.5604862890E-03 1.2651834412E-02 + 1.2583160895E+01 1.8895529481E+01 6.2925501368E+00 +:V: + -9.4484411195E-06 6.8789338098E-04 4.3970900958E-04 + 3.4804027949E-05 -1.5741701959E-04 5.1705082639E-04 + 6.5972456348E-04 -4.5424658069E-04 -3.0803376886E-04 + -3.1351526160E-04 -1.3659632601E-04 -4.4896791509E-04 + 3.0231441802E-04 4.0502413458E-04 -3.3982899282E-05 + -1.5574372453E-04 3.6991130792E-04 -5.9833142978E-05 + -7.7856171674E-04 -5.9303106887E-04 2.6605522076E-04 + 5.8692139562E-05 1.3131386257E-04 3.9300084580E-04 + 4.7145998336E-04 -4.7432753309E-04 1.4675868220E-04 + -4.4385843539E-04 -2.7034853268E-05 -6.1806151059E-04 + 2.4039180796E-05 1.9166724976E-05 -3.0829527994E-04 + 8.2862515369E-05 -4.7534537762E-04 4.3504060836E-04 + 5.3386575470E-04 -4.6997188735E-05 3.8076563780E-04 + 7.7038289373E-04 3.4867641814E-04 -5.1146995483E-05 + -7.1354531134E-04 5.7144731524E-04 -2.9860793623E-04 + 4.5255463254E-05 -8.3794172302E-04 -5.9082998333E-05 + -3.3702319544E-04 5.9695672618E-04 -2.8157920658E-05 + -1.5872401267E-04 9.7191498432E-06 -4.3013651466E-04 + 1.9930951290E-04 1.8282177225E-04 3.1755151275E-04 + -3.6325384571E-04 -4.1683344847E-05 -1.6945507706E-04 +:F: + -3.2321823115E-03 7.6277251560E-04 4.9923619117E-04 + -2.8843265328E-03 -3.5042897341E-04 -1.0341191153E-05 + 1.1740811173E-02 -3.3794984505E-04 -4.4026915438E-04 + 1.2298082023E-02 -4.7081675663E-04 -4.4069372594E-05 + 1.2398548629E-02 2.5151373328E-05 1.0125942987E-04 + 1.3492045756E-02 5.8033710132E-04 7.0789424468E-05 + 1.2209897235E-02 -3.3230274295E-04 1.2937846809E-04 + 1.2719453029E-02 3.4024638914E-04 -8.2307551185E-05 + 1.3436959319E-02 -1.7200542985E-04 -1.0993539128E-04 + 2.4091893910E-03 3.8392830409E-04 -2.2185343675E-04 + 3.6240927525E-03 -3.5234529905E-04 -4.7035636238E-04 + -1.1722881387E-02 -5.2218072424E-04 6.2638087742E-04 + -1.2308659056E-02 1.2676191634E-05 4.3289985449E-04 + -1.2352059663E-02 -3.5921092060E-04 -1.0869011627E-04 + -1.3488451508E-02 5.3264347196E-04 -4.3487916505E-04 + -1.2283025395E-02 -3.3716535377E-04 2.7060666007E-04 + -1.2706379458E-02 6.1690048344E-04 3.7173412939E-05 + -1.3467308608E-02 -2.2335020909E-05 -2.6756202262E-04 + 6.4920810208E-04 -6.0797478576E-05 1.2200933657E-02 + -5.3301348892E-04 6.2882714521E-05 -1.2178394211E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483296790E+03 +:LATVEC_SCALE: + 1.8897255184E+01 1.8897255184E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0584561253E-01 -7.8707928744E-02 1.3854898229E-01 + -7.8707928744E-02 7.2250665787E-01 -2.8777820423E-02 + 1.3854898229E-01 -2.8777820423E-02 4.6289176630E-01 +:STRESS: + 4.9428972635E+00 -1.6144024062E-03 1.5543670367E-03 + -1.6144024062E-03 5.5295866039E+00 6.0879356481E-04 + 1.5543670367E-03 6.0879356481E-04 5.8009798024E+00 +:CONSTRESS: + 5.6532770567E-01 -1.5310518768E-01 1.3668393567E-01 + -1.5310518768E-01 -5.6532770567E-01 -2.9607617028E-02 + 1.3668393567E-01 -2.9607617028E-02 -5.4393647086E+00 +:TOTSTRESS: + -4.8023793566E+00 7.6011661338E-02 3.1067958194E-04 + 7.6011661338E-02 -4.2417522403E+00 2.2100303971E-04 + 3.1067958194E-04 2.2100303971E-04 1.0127667250E-01 +:PRESIO: 6.3041467890E-01 +:PRES: -5.4244878899E+00 +:CONPRES: -1.8131215695E+00 +:TOTPRES: -2.9809516415E+00 +:PRESIG: 6.6359439884E-01 +:MIND: +Al - Al: 6.2556433640E+00 +C - C: 6.2799480630E+00 +Al - C: 6.2831548586E+00 + + +:MDSTEP: 3 +:MDTM: 73.34 +:TWIST: 0 +:TEL: 2400 +:TIO: 2409.6622266793 +:TEN: -2.6048845791E+00 +:KEN: 1.0874098340E-02 +:KENIG: 1.1446419305E-02 +:FEN: -2.6157586774E+00 +:UEN: -2.6085668773E+00 +:TSEN: -7.1918000697E-03 +:NPT_NP_HAMIL: 2.4770549961E-05 +:SNOSE[0]: 1.0000547642E+00 +:SNOSE[1]: 2.6230834327E-06 +:R: + 1.8896464571E+01 5.6876197816E-02 3.6355917880E-02 + 2.8776577480E-03 1.8884230275E+01 6.3418310058E+00 + 5.4547146806E-02 1.8859687900E+01 1.2572691883E+01 + 1.8871323800E+01 6.2877816113E+00 1.8860138425E+01 + 2.4995865989E-02 6.3325637147E+00 6.2962705634E+00 + 1.8884368619E+01 6.3296605260E+00 1.2593213549E+01 + 1.8832872966E+01 1.2549118436E+01 2.1997915856E-02 + 4.8527602772E-03 1.2609008511E+01 6.3315743342E+00 + 3.8981109381E-02 1.2558933047E+01 1.2610294926E+01 + 6.2623766546E+00 1.8895010494E+01 1.8846157468E+01 + 6.3010632271E+00 1.5847376809E-03 6.2735899311E+00 + 6.3059268480E+00 1.8857943416E+01 1.2634130585E+01 + 6.3432165654E+00 6.2951898206E+00 3.1482375747E-02 + 6.3627722059E+00 6.3279047896E+00 6.2948514056E+00 + 6.2400784911E+00 6.3463238669E+00 1.2573471227E+01 + 6.3028174330E+00 1.2528868806E+01 1.8892374799E+01 + 6.2712099816E+00 1.2647508657E+01 6.2967521829E+00 + 6.2859520625E+00 1.2598954853E+01 1.2562596212E+01 + 1.2614630507E+01 1.5116016057E-02 2.6255707321E-02 + 1.2568116810E+01 1.8893799332E+01 6.2850694973E+00 +:V: + -1.2185519769E-05 6.8882275506E-04 4.4017918471E-04 + 3.2504562384E-05 -1.5784919363E-04 5.1714904609E-04 + 6.6956230973E-04 -4.5465349357E-04 -3.0857197928E-04 + -3.0325855949E-04 -1.3707796818E-04 -4.4905191641E-04 + 3.1267353291E-04 4.0513560765E-04 -3.3801454151E-05 + -1.4430511412E-04 3.7064631288E-04 -5.9739447928E-05 + -7.6838903675E-04 -5.9352903425E-04 2.6615204391E-04 + 6.9466927958E-05 1.3163351387E-04 3.9292920366E-04 + 4.8279552817E-04 -4.7454153341E-04 1.4661073315E-04 + -4.4213334520E-04 -2.6547892071E-05 -6.1844803474E-04 + 2.7269074945E-05 1.8723362547E-05 -3.0873512070E-04 + 7.3008907216E-05 -4.7598033573E-04 4.3580555543E-04 + 5.2358313383E-04 -4.6876141879E-05 3.8123996759E-04 + 7.6003101948E-04 3.4830675526E-04 -5.1231833225E-05 + -7.2493596723E-04 5.7211445435E-04 -2.9913983428E-04 + 3.5025589616E-05 -8.3842892341E-04 -5.8791568930E-05 + -3.4776437012E-04 5.9760001663E-04 -2.8058154938E-05 + -1.7011528357E-04 9.6710103989E-06 -4.3044966953E-04 + 2.0113115847E-04 1.8264380602E-04 3.4090586868E-04 + -3.6474425615E-04 -4.1500712814E-05 -1.9274826713E-04 +:F: + -3.2817896495E-03 1.5314093571E-03 6.7296215198E-04 + -2.5830360970E-03 -6.9685474170E-04 3.0687106028E-04 + 1.1747334475E-02 -6.8494102417E-04 -8.7781186574E-04 + 1.2069864504E-02 -6.9167355845E-04 -2.1035935512E-04 + 1.2287183615E-02 2.8882450964E-04 3.2635162864E-04 + 1.3707205782E-02 1.2130890158E-03 1.4488447209E-04 + 1.1902165725E-02 -9.2393906172E-04 1.3333843700E-04 + 1.2926046266E-02 4.3615671704E-04 -4.0412288402E-05 + 1.3592518345E-02 -3.9427236835E-04 -2.2427193351E-04 + 1.6422486515E-03 7.7152559832E-04 -7.7296019834E-04 + 4.0642718132E-03 -7.0031373560E-04 -6.1369476806E-04 + -1.1713656804E-02 -1.0458744756E-03 1.2466442524E-03 + -1.2094446948E-02 2.6969154727E-04 7.4201891049E-04 + -1.2187373790E-02 -4.7843905913E-04 -9.9395021854E-05 + -1.3701289306E-02 1.1235475774E-03 -8.6703647829E-04 + -1.2053361304E-02 -9.2293007300E-04 4.1566252831E-04 + -1.2892626913E-02 9.8561807251E-04 1.9679215567E-04 + -1.3657137928E-02 -9.1040859230E-05 -5.2984355482E-04 + 1.2910154503E-03 -1.1791797376E-04 1.2554163202E-02 + -1.0651358894E-03 1.2833453562E-04 -1.2503903335E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483229643E+03 +:LATVEC_SCALE: + 1.8897245782E+01 1.8897245782E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0668556663E-01 -8.1462137083E-02 1.3932641726E-01 + -8.1462137083E-02 7.2380116639E-01 -2.8358030832E-02 + 1.3932641726E-01 -2.8358030832E-02 4.6584822094E-01 +:STRESS: + 4.9333567827E+00 -3.2991247378E-03 2.5942414582E-03 + -3.2991247378E-03 5.5294424647E+00 1.6875208140E-03 + 2.5942414582E-03 1.6875208140E-03 5.8035224174E+00 +:CONSTRESS: + 5.7451476130E-01 -1.5518764093E-01 1.3625263697E-01 + -1.5518764093E-01 -5.7451476130E-01 -3.0241674314E-02 + 1.3625263697E-01 -3.0241674314E-02 -5.4393379271E+00 +:TOTSTRESS: + -4.8011859773E+00 7.7024628583E-02 4.7953883032E-04 + 7.7024628583E-02 -4.2311265370E+00 1.9612266785E-04 + 4.7953883032E-04 1.9612266785E-04 1.0166373066E-01 +:PRESIO: 6.3211165132E-01 +:PRES: -5.4221072216E+00 +:CONPRES: -1.8131126424E+00 +:TOTPRES: -2.9768829279E+00 +:PRESIG: 6.6538068560E-01 +:MIND: +Al - Al: 6.2122901235E+00 +C - C: 6.2590141514E+00 +Al - C: 6.2670661158E+00 + + +:MDSTEP: 4 +:MDTM: 51.63 +:TWIST: 0 +:TEL: 2400 +:TIO: 2419.28744152944 +:TEN: -2.6048893425E+00 +:KEN: 1.0917534109E-02 +:KENIG: 1.1492141168E-02 +:FEN: -2.6158068767E+00 +:UEN: -2.6086257928E+00 +:TSEN: -7.1810838645E-03 +:NPT_NP_HAMIL: 1.7839357701E-05 +:SNOSE[0]: 1.0002538806E+00 +:SNOSE[1]: 7.8257788815E-06 +:R: + 1.8895889745E+01 8.5376783285E-02 5.4563409864E-02 + 4.1764295668E-03 1.8877679033E+01 6.3632138608E+00 + 8.2429039667E-02 1.8840867817E+01 1.2559921113E+01 + 1.8858983541E+01 6.2820984813E+00 1.8841572196E+01 + 3.8134366956E-02 6.3493111913E+00 6.2948789735E+00 + 1.8878627491E+01 6.3449983700E+00 1.2590746601E+01 + 1.8801302618E+01 1.2524558179E+01 3.3002228159E-02 + 7.9488882936E-03 1.2614448046E+01 6.3478162482E+00 + 5.9174648865E-02 1.2539300598E+01 1.2616351516E+01 + 6.2441239467E+00 1.8893912386E+01 1.8820579093E+01 + 6.3022563624E+00 2.3465419993E-03 6.2608170060E+00 + 6.3087366308E+00 1.8838235471E+01 1.2652167250E+01 + 6.3646451945E+00 6.2932520801E+00 4.7254681786E-02 + 6.3939733061E+00 6.3422897929E+00 6.2927318953E+00 + 6.2098689635E+00 6.3699882773E+00 1.2561090544E+01 + 6.3040511915E+00 1.2494185098E+01 1.8889951738E+01 + 6.2566057076E+00 1.2672219473E+01 6.2955957545E+00 + 6.2786780166E+00 1.2599343645E+01 1.2544793398E+01 + 1.2622985684E+01 2.2661391475E-02 4.0837763800E-02 + 1.2552988349E+01 1.8892074722E+01 6.2766138314E+00 +:V: + -1.4964716749E-05 6.9029681912E-04 4.4073094137E-04 + 3.0452734936E-05 -1.5854698586E-04 5.1743604542E-04 + 6.7930235077E-04 -4.5528829720E-04 -3.0943010082E-04 + -2.9315517851E-04 -1.3772125702E-04 -4.4920759898E-04 + 3.2289332195E-04 4.0540659660E-04 -3.3426794999E-05 + -1.3266718231E-04 3.7185625989E-04 -5.9573422116E-05 + -7.5836347443E-04 -5.9444226510E-04 2.6621265829E-04 + 8.0404198925E-05 1.3201364549E-04 3.9283417740E-04 + 4.9418550260E-04 -4.7486966640E-04 1.4634319450E-04 + -4.4098185459E-04 -2.5730073943E-05 -6.1920471124E-04 + 3.0866519308E-05 1.7987204524E-05 -3.0924989624E-04 + 6.3154823455E-05 -4.7698495085E-04 4.3702279737E-04 + 5.1340758682E-04 -4.6532472086E-05 3.8191821234E-04 + 7.4970713116E-04 3.4778477780E-04 -5.1304415622E-05 + -7.3639534168E-04 5.7319382053E-04 -2.9998900447E-04 + 2.4984047733E-05 -8.3928565367E-04 -5.8369123068E-05 + -3.5860660982E-04 5.9846164767E-04 -2.7821949418E-05 + -1.8163768253E-04 9.5675691410E-06 -4.3091697651E-04 + 2.0412636392E-04 1.8233473916E-04 3.6490782306E-04 + -3.6718412186E-04 -4.1185908898E-05 -2.1665432881E-04 +:F: + -3.3375004446E-03 2.3013650928E-03 8.4853124565E-04 + -2.2843059353E-03 -1.0381143588E-03 6.2103710824E-04 + 1.1746644401E-02 -1.0402073019E-03 -1.3103570287E-03 + 1.1829656336E-02 -9.0380612747E-04 -3.7281626950E-04 + 1.2180015110E-02 5.4720887343E-04 5.4917599210E-04 + 1.3918995558E-02 1.8410323050E-03 2.2189392488E-04 + 1.1592669048E-02 -1.5292868062E-03 1.3698154821E-04 + 1.3133707004E-02 5.3054043471E-04 4.1209943413E-07 + 1.3739585328E-02 -6.1050363479E-04 -3.4291675709E-04 + 8.8932471142E-04 1.1620361876E-03 -1.3205835560E-03 + 4.5092489753E-03 -1.0426221804E-03 -7.5753299482E-04 + -1.1701261426E-02 -1.5693477798E-03 1.8563636203E-03 + -1.1872823999E-02 5.2597796160E-04 1.0525397912E-03 + -1.2021305713E-02 -5.9930013581E-04 -9.7595664561E-05 + -1.3910231055E-02 1.7149190502E-03 -1.2953635611E-03 + -1.1825590570E-02 -1.5114218909E-03 5.6175086556E-04 + -1.3072325076E-02 1.3467632199E-03 3.5199010843E-04 + -1.3842522841E-02 -1.5054421919E-04 -7.8607121380E-04 + 1.9240592367E-03 -1.7110703141E-04 1.2943461429E-02 + -1.5960386501E-03 1.9641834144E-04 -1.2860900687E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483128961E+03 +:LATVEC_SCALE: + 1.8897231685E+01 1.8897231685E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0855075629E-01 -8.4323239691E-02 1.4040654133E-01 + -8.4323239691E-02 7.2589408196E-01 -2.7980813710E-02 + 1.4040654133E-01 -2.7980813710E-02 4.6946772386E-01 +:STRESS: + 4.9222019892E+00 -5.0395282301E-03 3.0671405382E-03 + -5.0395282301E-03 5.5268915160E+00 3.2257146000E-03 + 3.0671405382E-03 3.2257146000E-03 5.8055169880E+00 +:CONSTRESS: + 5.8313255331E-01 -1.5736615397E-01 1.3668614922E-01 + -1.5736615397E-01 -5.8313255331E-01 -3.1376971274E-02 + 1.3668614922E-01 -3.1376971274E-02 -5.4381059259E+00 +:TOTSTRESS: + -4.7967837862E+00 7.8082442506E-02 6.5325156417E-04 + 7.8082442506E-02 -4.2178648807E+00 1.7044296372E-04 + 6.5325156417E-04 1.7044296372E-04 1.0205666181E-01 +:PRESIO: 6.3463752071E-01 +:PRES: -5.4182034977E+00 +:CONPRES: -1.8127019753E+00 +:TOTPRES: -2.9708640017E+00 +:PRESIG: 6.6803949548E-01 +:MIND: +Al - Al: 6.1690014902E+00 +C - C: 6.2362309653E+00 +Al - C: 6.2507564516E+00 + + +:MDSTEP: 5 +:MDTM: 58.81 +:TWIST: 0 +:TEL: 2400 +:TIO: 2431.37185230666 +:TEN: -2.6048998797E+00 +:KEN: 1.0972067508E-02 +:KENIG: 1.1549544745E-02 +:FEN: -2.6158719472E+00 +:UEN: -2.6087046452E+00 +:TSEN: -7.1673020759E-03 +:NPT_NP_HAMIL: 2.6423131892E-05 +:SNOSE[0]: 1.0007503101E+00 +:SNOSE[1]: 1.7076783762E-05 +:R: + 1.8895194476E+01 1.1394738551E-01 7.2794052238E-02 + 5.3953909372E-03 1.8871089313E+01 6.3846108594E+00 + 1.1070929799E-01 1.8822013459E+01 1.2547109260E+01 + 1.8847053854E+01 6.2763843676E+00 1.8822999467E+01 + 5.1691427546E-02 6.3660702750E+00 6.2935069460E+00 + 1.8873367218E+01 6.3603932604E+00 1.2588288219E+01 + 1.8770141311E+01 1.2499950222E+01 4.4007474749E-02 + 1.1500207762E-02 1.2619900986E+01 6.3640525317E+00 + 7.9838469128E-02 1.2519650650E+01 1.2622394088E+01 + 6.2259069303E+00 1.8892850333E+01 1.8794963730E+01 + 6.3036041691E+00 3.0718596702E-03 6.2480222031E+00 + 6.3111373617E+00 1.8818475178E+01 1.2670262137E+01 + 6.3856523219E+00 6.2913317217E+00 6.3058071902E-02 + 6.4247443402E+00 6.3566473967E+00 6.2906097311E+00 + 6.1791851519E+00 6.3937024508E+00 1.2548669162E+01 + 6.3048721281E+00 1.2459457840E+01 1.8887549035E+01 + 6.2415508198E+00 1.2696965332E+01 6.2944519564E+00 + 6.2709240450E+00 1.2599723941E+01 1.2526969463E+01 + 1.2631484974E+01 3.0190783666E-02 5.6424872945E-02 + 1.2537737474E+01 1.8890361344E+01 6.2671574267E+00 +:V: + -1.7788337871E-05 6.9221102241E-04 4.4129971192E-04 + 2.8643053678E-05 -1.5948172306E-04 5.1783122597E-04 + 6.8883335414E-04 -4.5608927456E-04 -3.1055681304E-04 + -2.8317506946E-04 -1.3849746237E-04 -4.4936461330E-04 + 3.3292533316E-04 4.0577164540E-04 -3.2856231397E-05 + -1.2081744750E-04 3.7348029455E-04 -5.9323796395E-05 + -7.4837635378E-04 -5.9569191752E-04 2.6619683067E-04 + 9.1488620247E-05 1.3243318561E-04 3.9265669615E-04 + 5.0554443930E-04 -4.7523584103E-04 1.4593066753E-04 + -4.4032630508E-04 -2.4575408902E-05 -6.2023388361E-04 + 3.4829625798E-05 1.6960959919E-05 -3.0979312222E-04 + 5.3296854080E-05 -4.7828690926E-04 4.3861559989E-04 + 5.0327209524E-04 -4.5961317544E-05 3.8274362051E-04 + 7.3930386157E-04 3.4705750269E-04 -5.1363254087E-05 + -7.4780508702E-04 5.7459892655E-04 -3.0110631849E-04 + 1.5129007124E-05 -8.4038727403E-04 -5.7806386057E-05 + -3.6948678129E-04 5.9944547869E-04 -2.7448889629E-05 + -1.9325584625E-04 9.4156374883E-06 -4.3146880616E-04 + 2.0824681092E-04 1.8187473956E-04 3.8956326023E-04 + -3.7051572008E-04 -4.0727720808E-05 -2.4119341371E-04 +:F: + -3.4003727020E-03 3.0676224342E-03 1.0254444603E-03 + -1.9869523626E-03 -1.3732990209E-03 9.3031888358E-04 + 1.1737667845E-02 -1.4024868706E-03 -1.7364493645E-03 + 1.1577788066E-02 -1.1057942145E-03 -5.3118592632E-04 + 1.2076784207E-02 7.9922323435E-04 7.6925470270E-04 + 1.4127165728E-02 2.4621808458E-03 3.0186533239E-04 + 1.1283342005E-02 -2.1451565319E-03 1.3964476987E-04 + 1.3342050785E-02 6.2349379056E-04 4.0959156894E-05 + 1.3877081317E-02 -8.2046377838E-04 -4.6609669605E-04 + 1.5148440899E-04 1.5556680930E-03 -1.8597757310E-03 + 4.9592553102E-03 -1.3785771022E-03 -9.0042509687E-04 + -1.1686429891E-02 -2.0912128093E-03 2.4503418521E-03 + -1.1644912879E-02 7.7848780202E-04 1.3627684893E-03 + -1.1855309376E-02 -7.2181403468E-04 -1.0301060493E-04 + -1.4112730357E-02 2.3044763273E-03 -1.7179294892E-03 + -1.1600157398E-02 -2.0991987019E-03 7.0862308596E-04 + -1.3245118238E-02 1.6998225338E-03 5.0301295452E-04 + -1.4022835136E-02 -1.9976991705E-04 -1.0359802069E-03 + 2.5483745579E-03 -2.2060392377E-04 1.3370116831E-02 + -2.1261758900E-03 2.6740184393E-04 -1.3251497403E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7482994763E+03 +:LATVEC_SCALE: + 1.8897212896E+01 1.8897212896E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.1122579899E-01 -8.7265068552E-02 1.4175671733E-01 + -8.7265068552E-02 7.2857160762E-01 -2.7639827472E-02 + 1.4175671733E-01 -2.7639827472E-02 4.7362905892E-01 +:STRESS: + 4.9094635718E+00 -6.8320051570E-03 2.9347149451E-03 + -6.8320051570E-03 5.5219073469E+00 5.2148560702E-03 + 2.9347149451E-03 5.2148560702E-03 5.8069574759E+00 +:CONSTRESS: + 5.9111001615E-01 -1.5961205228E-01 1.3798999169E-01 + -1.5961205228E-01 -5.9111001615E-01 -3.2998570894E-02 + 1.3798999169E-01 -3.2998570894E-02 -5.4357840828E+00 +:TOTSTRESS: + -4.7893477890E+00 7.9178988886E-02 8.3201069508E-04 + 7.9178988886E-02 -4.2022257231E+00 1.4388735132E-04 + 8.3201069508E-04 1.4388735132E-04 1.0245566582E-01 +:PRESIO: 6.3780882184E-01 +:PRES: -5.4127761315E+00 +:CONPRES: -1.8119280276E+00 +:TOTPRES: -2.9630392821E+00 +:PRESIG: 6.7137770720E-01 +:MIND: +Al - Al: 6.1257461179E+00 +C - C: 6.2115504974E+00 +Al - C: 6.2341705699E+00 + + +:MDSTEP: 6 +:MDTM: 54.96 +:TWIST: 0 +:TEL: 2400 +:TIO: 2445.01716253367 +:TEN: -2.6049200602E+00 +:KEN: 1.1033644788E-02 +:KENIG: 1.1614362935E-02 +:FEN: -2.6159537050E+00 +:UEN: -2.6088033788E+00 +:TSEN: -7.1503262045E-03 +:NPT_NP_HAMIL: 5.6299311422E-05 +:SNOSE[0]: 1.0017304725E+00 +:SNOSE[1]: 3.1089043483E-05 +:R: + 1.8894376908E+01 1.4260343460E-01 9.1046870713E-02 + 6.5444411875E-03 1.8864452051E+01 6.4060243959E+00 + 1.3937634620E-01 1.8803119602E+01 1.2534246540E+01 + 1.8835530386E+01 6.2706344971E+00 1.8804421981E+01 + 6.5657928571E-02 6.3828431719E+00 6.2921626477E+00 + 1.8868596785E+01 6.3758607292E+00 1.2585842134E+01 + 1.8739390198E+01 1.2475282791E+01 5.5009458382E-02 + 1.5512301686E-02 1.2625368414E+01 6.3802782683E+00 + 1.0096900986E-01 1.2499983576E+01 1.2628416016E+01 + 6.2077070577E+00 1.8891838386E+01 1.8769302658E+01 + 6.3051216557E+00 3.7487609343E-03 6.2352055589E+00 + 6.3131288561E+00 1.8798652135E+01 1.2688428790E+01 + 6.4062379150E+00 6.2894382501E+00 7.8897143453E-02 + 6.4550793223E+00 6.3709677581E+00 6.2884855537E+00 + 6.1480322646E+00 6.4174775819E+00 1.2536197269E+01 + 6.3052879912E+00 1.2424680178E+01 1.8885172714E+01 + 6.2260454491E+00 1.2721748815E+01 6.2933264721E+00 + 6.2626871874E+00 1.2600093877E+01 1.2509122685E+01 + 1.2640173676E+01 3.7697403796E-02 7.3043656704E-02 + 1.2522328832E+01 1.8888665384E+01 6.2566740827E+00 +:V: + -2.0657111325E-05 6.9442983773E-04 4.4180363644E-04 + 2.7070704681E-05 -1.6061777173E-04 5.1823278514E-04 + 6.9801415681E-04 -4.5697634192E-04 -3.1188681253E-04 + -2.7328227213E-04 -1.3937123817E-04 -4.4943595814E-04 + 3.4270451853E-04 4.0614950683E-04 -3.2086551544E-05 + -1.0874464773E-04 3.7544080925E-04 -5.8977405363E-05 + -7.3829430118E-04 -5.9717351128E-04 2.6605411349E-04 + 1.0269574663E-04 1.3286603658E-04 3.9232418402E-04 + 5.1676199989E-04 -4.7554595213E-04 1.4534263993E-04 + -4.4007221128E-04 -2.3078393241E-05 -6.2140996288E-04 + 3.9153098188E-05 1.5648204083E-05 -3.1030587228E-04 + 4.3433419695E-05 -4.7979419264E-04 4.4048580705E-04 + 4.9309506223E-04 -4.5158393932E-05 3.8364357418E-04 + 7.2869037128E-04 3.4605985210E-04 -5.1404771702E-05 + -7.5901278512E-04 5.7621936461E-04 -3.0242936651E-04 + 5.4616767060E-06 -8.4157485186E-04 -5.7092469487E-05 + -3.8032260158E-04 6.0043221194E-04 -2.6937763112E-05 + -2.0492101980E-04 9.2224486245E-06 -4.3201914391E-04 + 2.1343278698E-04 1.8123808117E-04 4.1485551197E-04 + -3.7466562928E-04 -4.0113750618E-05 -2.6636980624E-04 +:F: + -3.4703418793E-03 3.8244348411E-03 1.2020403231E-03 + -1.6896729298E-03 -1.7020180582E-03 1.2316823913E-03 + 1.1720530588E-02 -1.7701100764E-03 -2.1529192645E-03 + 1.1314239443E-02 -1.2964095939E-03 -6.8530125269E-04 + 1.1977980729E-02 1.0441666520E-03 9.8639733414E-04 + 1.4332024376E-02 3.0735527712E-03 3.8452402242E-04 + 1.0977012091E-02 -2.7674063107E-03 1.4066487669E-04 + 1.3550230133E-02 7.1499048683E-04 8.2074215083E-05 + 1.4003328699E-02 -1.0232609483E-03 -5.9377173862E-04 + -5.7060340905E-04 1.9507440071E-03 -2.3844601683E-03 + 5.4139538430E-03 -1.7069350355E-03 -1.0417642652E-03 + -1.1670358738E-02 -2.6094291008E-03 3.0232542362E-03 + -1.1411719321E-02 1.0258979164E-03 1.6710378390E-03 + -1.1691215174E-02 -8.4573375325E-04 -1.1546180882E-04 + -1.4307756870E-02 2.8895654749E-03 -2.1328779396E-03 + -1.1378681739E-02 -2.6827058000E-03 8.5619632253E-04 + -1.3409985429E-02 2.0435498693E-03 6.4975979813E-04 + -1.4196632820E-02 -2.3820998652E-04 -1.2790634134E-03 + 3.1627376640E-03 -2.6571257158E-04 1.3836659993E-02 + -2.6550692583E-03 3.4102921634E-04 -1.3678671501E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7482827028E+03 +:LATVEC_SCALE: + 1.8897189410E+01 1.8897189410E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.1443788246E-01 -9.0252172784E-02 1.4333285071E-01 + -9.0252172784E-02 7.3156006630E-01 -2.7327047435E-02 + 1.4333285071E-01 -2.7327047435E-02 4.7817180404E-01 +:STRESS: + 4.8951586473E+00 -8.6699671991E-03 2.1697827075E-03 + -8.6699671991E-03 5.5144662817E+00 7.6093773800E-03 + 2.1697827075E-03 7.6093773800E-03 5.8078033933E+00 +:CONSTRESS: + 5.9838515121E-01 -1.6187085586E-01 1.4014697492E-01 + -1.6187085586E-01 -5.9838515121E-01 -3.5052894935E-02 + 1.4014697492E-01 -3.5052894935E-02 -5.4324920584E+00 +:TOTSTRESS: + -4.7791059161E+00 8.0288650273E-02 1.0160930786E-03 + 8.0288650273E-02 -4.1845210642E+00 1.1647012018E-04 + 1.0160930786E-03 1.1647012018E-04 1.0286046916E-01 +:PRESIO: 6.4138991760E-01 +:PRES: -5.4058094408E+00 +:CONPRES: -1.8108306861E+00 +:TOTPRES: -2.9535888370E+00 +:PRESIG: 6.7514728168E-01 +:MIND: +Al - Al: 6.0825014947E+00 +C - C: 6.1849259554E+00 +Al - C: 6.2172563557E+00 + + +:MDSTEP: 7 +:MDTM: 58.61 +:TWIST: 0 +:TEL: 2400 +:TIO: 2459.18830058698 +:TEN: -2.6049562382E+00 +:KEN: 1.1097594974E-02 +:KENIG: 1.1681678921E-02 +:FEN: -2.6160538332E+00 +:UEN: -2.6089237918E+00 +:TSEN: -7.1300413423E-03 +:NPT_NP_HAMIL: 7.4854324517E-05 +:SNOSE[0]: 1.0034043928E+00 +:SNOSE[1]: 5.0242638988E-05 +:R: + 1.8893435192E+01 1.7135430794E-01 1.0931727223E-01 + 7.6333036289E-03 1.8857759748E+01 6.4274523624E+00 + 1.6841235749E-01 1.8784184575E+01 1.2521326091E+01 + 1.8824410275E+01 6.2648456518E+00 1.8785845282E+01 + 8.0021805067E-02 6.3996285231E+00 6.2908543759E+00 + 1.8864325540E+01 6.3914128422E+00 1.2583412636E+01 + 1.8709056204E+01 1.2450548792E+01 6.6001768237E-02 + 1.9989546199E-02 1.2630850263E+01 6.3964853849E+00 + 1.2255775618E-01 1.2480303867E+01 1.2634409360E+01 + 6.1895099029E+00 1.8890890769E+01 1.8743592751E+01 + 6.3068235250E+00 4.3655006088E-03 6.2223697035E+00 + 6.3147109361E+00 1.8778760011E+01 1.2706676372E+01 + 6.4263984422E+00 6.2875813257E+00 9.4773275511E-02 + 6.4849666195E+00 6.3852382054E+00 6.2863601780E+00 + 6.1164222982E+00 6.4413199640E+00 1.2523667826E+01 + 6.3053066541E+00 1.2389852280E+01 1.8882829266E+01 + 6.2100934420E+00 1.2746567261E+01 6.2922250367E+00 + 6.2539667524E+00 1.2600451892E+01 1.2491255114E+01 + 1.2649094388E+01 4.5173355657E-02 9.0719644399E-02 + 1.2506730359E+01 1.8886993530E+01 6.2451377389E+00 +:V: + -2.3569495861E-05 6.9679621092E-04 4.4214972076E-04 + 2.5731719278E-05 -1.6191460176E-04 5.1852476112E-04 + 7.0668347880E-04 -4.5785770228E-04 -3.1334440672E-04 + -2.6343989008E-04 -1.4030262259E-04 -4.4932460123E-04 + 3.5215333106E-04 4.0644915675E-04 -3.1114819182E-05 + -9.6441879836E-05 3.7764807206E-04 -5.8520223668E-05 + -7.2797146359E-04 -5.9876475723E-04 2.6572795133E-04 + 1.1399173910E-04 1.3328295118E-04 3.9175626323E-04 + 5.2770909294E-04 -4.7569436547E-04 1.4454617295E-04 + -4.4011434646E-04 -2.1235027114E-05 -6.2258827087E-04 + 4.3827775371E-05 1.4053971479E-05 -3.1072164391E-04 + 3.3566331144E-05 -4.8140135346E-04 4.4252003579E-04 + 4.8278877432E-04 -4.4121245451E-05 3.8453485314E-04 + 7.1772460435E-04 3.4472065112E-04 -5.1423815760E-05 + -7.6984224289E-04 5.7792853187E-04 -3.0388661693E-04 + -4.0124962329E-06 -8.4266685201E-04 -5.6215770045E-05 + -3.9101661264E-04 6.0128759425E-04 -2.6287346224E-05 + -2.1657225209E-04 8.9955688309E-06 -4.3247177265E-04 + 2.1961280962E-04 1.8039579056E-04 4.4074830691E-04 + -3.7954804500E-04 -3.9331116051E-05 -2.9217231453E-04 +:F: + -3.5471653159E-03 4.5665911524E-03 1.3771653102E-03 + -1.3917978973E-03 -2.0235232625E-03 1.5222079279E-03 + 1.1695261385E-02 -2.1422971836E-03 -2.5569276053E-03 + 1.1040009775E-02 -1.4746436305E-03 -8.3489165549E-04 + 1.1883853430E-02 1.2813200400E-03 1.2000458214E-03 + 1.4534098060E-02 3.6725491305E-03 4.6983867552E-04 + 1.0675687281E-02 -3.3917914857E-03 1.3958094125E-04 + 1.3757596621E-02 8.0515261032E-04 1.2405063457E-04 + 1.4117222551E-02 -1.2175548871E-03 -7.2542097749E-04 + -1.2758914632E-03 2.3471308973E-03 -2.8898702395E-03 + 5.8733883648E-03 -2.0272065747E-03 -1.1810154385E-03 + -1.1654830934E-02 -3.1218579266E-03 3.5705705516E-03 + -1.1174763762E-02 1.2645343015E-03 1.9753359794E-03 + -1.1530564651E-02 -9.6976144418E-04 -1.3409354288E-04 + -1.4494142114E-02 3.4673185406E-03 -2.5385766185E-03 + -1.1161701272E-02 -3.2577066944E-03 1.0046461578E-03 + -1.3566281161E-02 2.3764332809E-03 7.9201376874E-04 + -1.4362953745E-02 -2.6545497090E-04 -1.5149460078E-03 + 3.7653148924E-03 -3.0693103854E-04 1.4345535805E-02 + -3.1823400436E-03 4.1769914514E-04 -1.4145249488E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7482625657E+03 +:LATVEC_SCALE: + 1.8897161215E+01 1.8897161215E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.1787516531E-01 -9.3241153140E-02 1.4508264380E-01 + -9.3241153140E-02 7.3454470903E-01 -2.7033640080E-02 + 1.4508264380E-01 -2.7033640080E-02 4.8290799864E-01 +:STRESS: + 4.8794211850E+00 -1.0544106174E-02 7.2228612136E-04 + -1.0544106174E-02 5.5046697096E+00 1.0377696786E-02 + 7.2228612136E-04 1.0377696786E-02 5.8081699124E+00 +:CONSTRESS: + 6.0491480032E-01 -1.6407703815E-01 1.4315476030E-01 + -1.6407703815E-01 -6.0491480032E-01 -3.7499409060E-02 + 1.4315476030E-01 -3.7499409060E-02 -5.4285327212E+00 +:TOTSTRESS: + -4.7664608200E+00 8.1379991188E-02 1.2055973773E-03 + 8.1379991188E-02 -4.1652102002E+00 8.8072194056E-05 + 1.2055973773E-03 8.8072194056E-05 1.0327080743E-01 +:PRESIO: 6.4510929099E-01 +:PRES: -5.3974202690E+00 +:CONPRES: -1.8095109071E+00 +:TOTPRES: -2.9428000709E+00 +:PRESIG: 6.7906241157E-01 +:MIND: +Al - Al: 6.0392555806E+00 +C - C: 6.1563132010E+00 +Al - C: 6.1999656727E+00 + + +:MDSTEP: 8 +:MDTM: 51.26 +:TWIST: 0 +:TEL: 2400 +:TIO: 2472.7755315492 +:TEN: -2.6050138778E+00 +:KEN: 1.1158910160E-02 +:KENIG: 1.1746221221E-02 +:FEN: -2.6161727879E+00 +:UEN: -2.6090663730E+00 +:TSEN: -7.1064148919E-03 +:NPT_NP_HAMIL: 7.2692701679E-05 +:SNOSE[0]: 1.0059938019E+00 +:SNOSE[1]: 7.4560750189E-05 +:R: + 1.8892367574E+01 2.0020263785E-01 1.2759672071E-01 + 8.6715533398E-03 1.8851006624E+01 6.4488877132E+00 + 1.9779261665E-01 1.8765210592E+01 1.2508344307E+01 + 1.8813692103E+01 6.2590163169E+00 1.8767279006E+01 + 9.4767616178E-02 6.4164211148E+00 6.2895905255E+00 + 1.8860562959E+01 6.4070577992E+00 1.2581004596E+01 + 1.8679152288E+01 1.2425746381E+01 7.6975610400E-02 + 2.4934736849E-02 1.2636345220E+01 6.4126624356E+00 + 1.4459060993E-01 1.2460620475E+01 1.2640364819E+01 + 6.1713054930E+00 1.8890021819E+01 1.8717837076E+01 + 6.3087240144E+00 4.9105783518E-03 6.2095200830E+00 + 6.3158835842E+00 1.8758796967E+01 1.2725009170E+01 + 6.4461267649E+00 6.2857706277E+00 1.1068429125E-01 + 6.5143887193E+00 6.3994431086E+00 6.2842346561E+00 + 6.0843748140E+00 6.4652304715E+00 1.2511076855E+01 + 6.3049363173E+00 1.2354982049E+01 1.8880525652E+01 + 6.1937028837E+00 1.2771412301E+01 6.2911534235E+00 + 6.2447647690E+00 1.2600796735E+01 1.2473372859E+01 + 1.2658286508E+01 5.2609511406E-02 1.0947652249E-01 + 1.2490913698E+01 1.8885352988E+01 6.2325230984E+00 +:V: + -2.6522031695E-05 6.9914048901E-04 4.4224028929E-04 + 2.4622800812E-05 -1.6332838653E-04 5.1858475500E-04 + 7.1466936509E-04 -4.5863620750E-04 -3.1484811028E-04 + -2.5361372152E-04 -1.4124804613E-04 -4.4892992322E-04 + 3.6118554602E-04 4.0657539263E-04 -2.9939344526E-05 + -8.3909970444E-05 3.8000479904E-04 -5.7938076923E-05 + -7.1726115778E-04 -6.0033380958E-04 2.6515961488E-04 + 1.2533401867E-04 1.3365322879E-04 3.9087016432E-04 + 5.3824476146E-04 -4.7557041710E-04 1.4350840848E-04 + -4.4034186661E-04 -1.9043170197E-05 -6.2361379725E-04 + 4.8840479450E-05 1.2184797657E-05 -3.1097060074E-04 + 2.3702047281E-05 -4.8299563811E-04 4.4459544001E-04 + 4.7226648116E-04 -4.2850941868E-05 3.8532880281E-04 + 7.0626487499E-04 3.4296811402E-04 -5.1414369336E-05 + -7.8010273924E-04 5.7959110122E-04 -3.0540121223E-04 + -1.3282701634E-05 -8.4347042629E-04 -5.5164923777E-05 + -4.0146101263E-04 6.0187094134E-04 -2.5497163128E-05 + -2.2813863089E-04 8.7429878607E-06 -4.3272616802E-04 + 2.2670444982E-04 1.7931777653E-04 4.6718838245E-04 + -3.8506804782E-04 -3.8366830974E-05 -3.1857490707E-04 +:F: + -3.6315506960E-03 5.2878990288E-03 1.5498677462E-03 + -1.0928798938E-03 -2.3366670636E-03 1.8002144571E-03 + 1.1661860176E-02 -2.5179060780E-03 -2.9467098866E-03 + 1.0756640317E-02 -1.6374295321E-03 -9.8008137528E-04 + 1.1793526604E-02 1.5099991856E-03 1.4094305150E-03 + 1.4731749534E-02 4.2559300307E-03 5.5813226228E-04 + 1.0380617826E-02 -4.0150884941E-03 1.3594038815E-04 + 1.3963569357E-02 8.9371859132E-04 1.6721115291E-04 + 1.4217737814E-02 -1.4021181627E-03 -8.6044177562E-04 + -1.9624584322E-03 2.7442962108E-03 -3.3708307560E-03 + 6.3373157419E-03 -2.3395489287E-03 -1.3174421707E-03 + -1.1641024361E-02 -3.6260483601E-03 4.0871427281E-03 + -1.0936093326E-02 1.4912675138E-03 2.2740113290E-03 + -1.1373851536E-02 -1.0929145584E-03 -1.5872452292E-04 + -1.4669001974E-02 4.0347451018E-03 -2.9330045879E-03 + -1.0949320401E-02 -3.8202234925E-03 1.1540502792E-03 + -1.3713475021E-02 2.6978647253E-03 9.2920647499E-04 + -1.4520836156E-02 -2.8116816905E-04 -1.7429817765E-03 + 4.3542944673E-03 -3.4420864379E-04 1.4898786175E-02 + -3.7068200429E-03 4.9760109495E-04 -1.4653776657E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7482390434E+03 +:LATVEC_SCALE: + 1.8897128281E+01 1.8897128281E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.2120466467E-01 -9.6182776743E-02 1.4694830792E-01 + -9.6182776743E-02 7.3718864265E-01 -2.6750816399E-02 + 1.4694830792E-01 -2.6750816399E-02 4.8763420504E-01 +:STRESS: + 4.8622501282E+00 -1.2442610056E-02 -1.4421311251E-03 + -1.2442610056E-02 5.4925120633E+00 1.3482645166E-02 + -1.4421311251E-03 1.3482645166E-02 5.8080953786E+00 +:CONSTRESS: + 6.1067975590E-01 -1.6615776382E-01 1.4699025888E-01 + -1.6615776382E-01 -6.1067975590E-01 -4.0292067471E-02 + 1.4699025888E-01 -4.0292067471E-02 -5.4241474146E+00 +:TOTSTRESS: + -4.7517252194E+00 8.2417597136E-02 1.4001801639E-03 + 8.2417597136E-02 -4.1446436647E+00 5.8605906412E-05 + 1.4001801639E-03 5.8605906412E-05 1.0368624111E-01 +:PRESIO: 6.4867583746E-01 +:PRES: -5.3876191900E+00 +:CONPRES: -1.8080491382E+00 +:TOTPRES: -2.9308942143E+00 +:PRESIG: 6.8281667101E-01 +:MIND: +Al - Al: 5.9960077632E+00 +C - C: 6.1256720799E+00 +Al - C: 6.1822549967E+00 + + +:MDSTEP: 9 +:MDTM: 58.58 +:TWIST: 0 +:TEL: 2400 +:TIO: 2484.67737490712 +:TEN: -2.6050972743E+00 +:KEN: 1.1212619685E-02 +:KENIG: 1.1802757563E-02 +:FEN: -2.6163098940E+00 +:UEN: -2.6092304364E+00 +:TSEN: -7.0794576343E-03 +:NPT_NP_HAMIL: 6.1439239459E-05 +:SNOSE[0]: 1.0097175073E+00 +:SNOSE[1]: 1.0365127815E-04 +:R: + 1.8891172443E+01 2.2914401766E-01 1.4587270786E-01 + 9.6686441647E-03 1.8844188710E+01 6.4703184072E+00 + 2.2748534141E-01 1.8746203811E+01 1.2495300951E+01 + 1.8803375704E+01 6.2531468151E+00 1.8748736851E+01 + 1.0987629898E-01 6.4332118501E+00 6.2883795172E+00 + 1.8857318240E+01 6.4227997372E+00 1.2578623453E+01 + 1.8649697197E+01 1.2400879132E+01 8.7919817254E-02 + 3.0348765464E-02 1.2641850700E+01 6.4287946485E+00 + 1.6704759421E-01 1.2440946840E+01 1.2646271792E+01 + 6.1530884050E+00 1.8889245882E+01 1.8692045105E+01 + 6.3108367295E+00 5.3728014349E-03 6.1966649891E+00 + 6.3166471575E+00 1.8738765787E+01 1.2743426346E+01 + 6.4654123418E+00 6.2840156941E+00 1.2662437625E-01 + 6.5433225258E+00 6.4135639787E+00 6.2821102821E+00 + 6.0519172840E+00 6.4892043983E+00 1.2498423565E+01 + 6.3041857304E+00 1.2320085274E+01 1.8878269278E+01 + 6.1768863802E+00 1.2796269832E+01 6.2901173942E+00 + 6.2350863205E+00 1.2601127482E+01 1.2455486125E+01 + 1.2667785845E+01 5.9995555489E-02 1.2933554772E-01 + 1.2474854494E+01 1.8883751460E+01 6.2188061745E+00 +:V: + -2.9509576465E-05 7.0129201939E-04 4.4198111602E-04 + 2.3741580460E-05 -1.6481448887E-04 5.1829283329E-04 + 7.2180127071E-04 -4.5921697718E-04 -3.1631608576E-04 + -2.4377670846E-04 -1.4216220993E-04 -4.4815571885E-04 + 3.6971239301E-04 4.0643595852E-04 -2.8560546021E-05 + -7.1160273344E-05 3.8241206578E-04 -5.7217680396E-05 + -7.0602903605E-04 -6.0174964803E-04 2.6429296180E-04 + 1.3667277800E-04 1.3394678491E-04 3.8958799130E-04 + 5.4822560334E-04 -4.7506682426E-04 1.4219908070E-04 + -4.4064537403E-04 -1.6503673741E-05 -6.2433123653E-04 + 5.4173907346E-05 1.0049767035E-05 -3.1098477331E-04 + 1.3853248373E-05 -4.8446546846E-04 4.4658639805E-04 + 4.6145091829E-04 -4.1352630034E-05 3.8593811182E-04 + 6.9418288653E-04 3.4073554649E-04 -5.1370615520E-05 + -7.8960192673E-04 5.8107309109E-04 -3.0689605992E-04 + -2.2332727966E-05 -8.4379603462E-04 -5.3930347301E-05 + -4.1154435341E-04 6.0204583558E-04 -2.4567909377E-05 + -2.3954309854E-04 8.4733546301E-06 -4.3268494080E-04 + 2.3461603389E-04 1.7797630690E-04 4.9411113300E-04 + -3.9112627938E-04 -3.7208802640E-05 -3.4553987618E-04 +:F: + -3.7230770475E-03 5.9826472238E-03 1.7198251905E-03 + -7.9199687655E-04 -2.6404480186E-03 2.0624022934E-03 + 1.1618798474E-02 -2.8956361876E-03 -3.3198873650E-03 + 1.0465174910E-02 -1.7825731664E-03 -1.1207342662E-03 + 1.1706625819E-02 1.7295701193E-03 1.6137961831E-03 + 1.4923576842E-02 4.8204112258E-03 6.4964824403E-04 + 1.0093053132E-02 -4.6336816089E-03 1.2920223968E-04 + 1.4166832461E-02 9.8024523120E-04 2.1245912367E-04 + 1.4303878226E-02 -1.5756704339E-03 -9.9889096894E-04 + -2.6288655967E-03 3.1413449460E-03 -3.8209066574E-03 + 6.8048754770E-03 -2.6423543015E-03 -1.4499072896E-03 + -1.1628481918E-02 -4.1206698436E-03 4.5665911209E-03 + -1.0697124555E-02 1.7035344371E-03 2.5654415304E-03 + -1.1222114371E-02 -1.2154159620E-03 -1.8891324637E-04 + -1.4829377275E-02 4.5895805892E-03 -3.3145859425E-03 + -1.0741383683E-02 -4.3660823912E-03 1.3037146337E-03 + -1.3850540157E-02 3.0067984125E-03 1.0615716333E-03 + -1.4669592009E-02 -2.8476168925E-04 -1.9625230128E-03 + 4.9269142676E-03 -3.7788373312E-04 1.5498109327E-02 + -4.2271761197E-03 5.8104515114E-04 -1.5206412771E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7482120988E+03 +:LATVEC_SCALE: + 1.8897090554E+01 1.8897090554E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.2409615572E-01 -9.9025197020E-02 1.4887085090E-01 + -9.9025197020E-02 7.3915825261E-01 -2.6470507667E-02 + 1.4887085090E-01 -2.6470507667E-02 4.9214743697E-01 +:STRESS: + 4.8436384503E+00 -1.4363919458E-02 -4.3645942863E-03 + -1.4363919458E-02 5.4779692061E+00 1.6875802165E-02 + -4.3645942863E-03 1.6875802165E-02 5.8075508345E+00 +:CONSTRESS: + 6.1567423079E-01 -1.6802550548E-01 1.5163591387E-01 + -1.6802550548E-01 -6.1567423079E-01 -4.3374487037E-02 + 1.5163591387E-01 -4.3374487037E-02 -5.4195090910E+00 +:TOTSTRESS: + -4.7352165254E+00 8.3364227917E-02 1.5995313211E-03 + 8.3364227917E-02 -4.1231367228E+00 2.8177205422E-05 + 1.5995313211E-03 2.8177205422E-05 1.0410569347E-01 +:PRESIO: 6.5180061510E-01 +:PRES: -5.3763861637E+00 +:CONPRES: -1.8065030303E+00 +:TOTPRES: -2.9180825182E+00 +:PRESIG: 6.8610591063E-01 +:MIND: +Al - Al: 5.9527691768E+00 +C - C: 6.0929675029E+00 +Al - C: 6.1640859315E+00 + + +:MDSTEP: 10 +:MDTM: 51.37 +:TWIST: 0 +:TEL: 2400 +:TIO: 2493.89920671669 +:TEN: -2.6052101072E+00 +:KEN: 1.1254235105E-02 +:KENIG: 1.1846563269E-02 +:FEN: -2.6164643423E+00 +:UEN: -2.6094150948E+00 +:TSEN: -7.0492474544E-03 +:NPT_NP_HAMIL: 5.3593611383E-05 +:SNOSE[0]: 1.0147752357E+00 +:SNOSE[1]: 1.3670551045E-04 +:R: + 1.8889848410E+01 2.5816724726E-01 1.6412908598E-01 + 1.0633957491E-02 1.8837303807E+01 6.4917276918E+00 + 2.5745202171E-01 1.8727174061E+01 1.2482199061E+01 + 1.8793461765E+01 6.2472393036E+00 1.8730236226E+01 + 1.2532523531E-01 6.4499880340E+00 6.2872296965E+00 + 1.8854599850E+01 6.4386388091E+00 1.2576275149E+01 + 1.8620714676E+01 1.2375955765E+01 9.8821061840E-02 + 3.6230372106E-02 1.2647362924E+01 6.4448642962E+00 + 1.8990298859E-01 1.2421300560E+01 1.2652118535E+01 + 6.1348575267E+00 1.8888577162E+01 1.8666232495E+01 + 6.3131744777E+00 5.7414290437E-03 6.1838153619E+00 + 6.3170026670E+00 1.8718673620E+01 1.2761921976E+01 + 6.4842418047E+00 6.2823257427E+00 1.4258428898E-01 + 6.5717401749E+00 6.4275797964E+00 6.2799885687E+00 + 6.0190848248E+00 6.5132317541E+00 1.2485710232E+01 + 6.3030643959E+00 1.2285185156E+01 1.8876067874E+01 + 6.1596610387E+00 1.2821120419E+01 6.2891226525E+00 + 6.2249396844E+00 1.2601443568E+01 1.2437608899E+01 + 1.2677624264E+01 6.7320140649E-02 1.5031526153E-01 + 1.2458532432E+01 1.8882197088E+01 6.2039646506E+00 +:V: + -3.2525327678E-05 7.0309320128E-04 4.4128986397E-04 + 2.3087021942E-05 -1.6633084240E-04 5.1754094802E-04 + 7.2792493606E-04 -4.5951624661E-04 -3.1767156654E-04 + -2.3391317285E-04 -1.4300209619E-04 -4.4691909830E-04 + 3.7765083091E-04 4.0594973237E-04 -2.6981555216E-05 + -5.8215572947E-05 3.8477657742E-04 -5.6347894903E-05 + -6.9416621289E-04 -6.0289288545E-04 2.6307977432E-04 + 1.4795394108E-04 1.3413669533E-04 3.8784450880E-04 + 5.5751695060E-04 -4.7408905005E-04 1.4059340804E-04 + -4.4092544832E-04 -1.3621188263E-05 -6.2459680636E-04 + 5.9807126603E-05 7.6618238009E-06 -3.1070417214E-04 + 4.0389556873E-06 -4.8571040408E-04 4.4837306762E-04 + 4.5028310820E-04 -3.9636076462E-05 3.8628416318E-04 + 6.8137659299E-04 3.3796798133E-04 -5.1287832042E-05 + -7.9816239228E-04 5.8225312029E-04 -3.0829968954E-04 + -3.1142251037E-05 -8.4347394309E-04 -5.2505627319E-05 + -4.2116018563E-04 6.0169130664E-04 -2.3501487558E-05 + -2.5070732399E-04 8.1966258367E-06 -4.3226261630E-04 + 2.4324921263E-04 1.7634943895E-04 5.2144980282E-04 + -3.9762552270E-04 -3.5846703276E-05 -3.7302413204E-04 +:F: + -3.8210269254E-03 6.6459943680E-03 1.8855330777E-03 + -4.8799038262E-04 -2.9344529522E-03 2.3053916427E-03 + 1.1566059136E-02 -3.2744006036E-03 -3.6731976086E-03 + 1.0166787990E-02 -1.9099329236E-03 -1.2572011898E-03 + 1.1623149305E-02 1.9399681086E-03 1.8126294278E-03 + 1.5108177508E-02 5.3628627334E-03 7.4461918295E-04 + 9.8147064597E-03 -5.2427430432E-03 1.1907249265E-04 + 1.4366527420E-02 1.0643104211E-03 2.6033988677E-04 + 1.4374063195E-02 -1.7370445790E-03 -1.1402885395E-03 + -3.2740224861E-03 3.5373277125E-03 -4.2341461837E-03 + 7.2750178706E-03 -2.9336106963E-03 -1.5776988499E-03 + -1.1617601351E-02 -4.6049047246E-03 5.0035980099E-03 + -1.0459123311E-02 1.8991708789E-03 2.8476878854E-03 + -1.1076609789E-02 -1.3367984924E-03 -2.2426871758E-04 + -1.4973360450E-02 5.1290693165E-03 -3.6813246070E-03 + -1.0538452620E-02 -4.8915686660E-03 1.4532227042E-03 + -1.3977021365E-02 3.3012105375E-03 1.1898322135E-03 + -1.4807445061E-02 -2.7466970282E-04 -2.1736918988E-03 + 5.4800613440E-03 -4.0804893400E-04 1.6145202774E-02 + -4.7418964872E-03 6.6826124138E-04 -1.5805311703E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7481816753E+03 +:LATVEC_SCALE: + 1.8897047956E+01 1.8897047956E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.2625074969E-01 -1.0171817656E-01 1.5079575344E-01 + -1.0171817656E-01 7.4015303759E-01 -2.6186159339E-02 + 1.5079575344E-01 -2.6186159339E-02 4.9626434241E-01 +:STRESS: + 4.8235955761E+00 -1.6307379890E-02 -8.0756141713E-03 + -1.6307379890E-02 5.4610145135E+00 2.0497039592E-02 + -8.0756141713E-03 2.0497039592E-02 5.8065524690E+00 +:CONSTRESS: + 6.1988148859E-01 -1.6958251119E-01 1.5706811151E-01 + -1.6958251119E-01 -6.1988148859E-01 -4.6680073250E-02 + 1.5706811151E-01 -4.6680073250E-02 -5.4148161415E+00 +:TOTSTRESS: + -4.7172263150E+00 8.4171714518E-02 1.8032560933E-03 + 8.4171714518E-02 -4.1009799874E+00 -3.1256813995E-06 + 1.8032560933E-03 -3.1256813995E-06 1.0452801485E-01 +:PRESIO: 6.5422270990E-01 +:PRES: -5.3637208529E+00 +:CONPRES: -1.8049387138E+00 +:TOTPRES: -2.9045594292E+00 +:PRESIG: 6.8865548410E-01 +:MIND: +Al - Al: 5.9095623164E+00 +C - C: 6.0581700398E+00 +Al - C: 6.1454254876E+00 diff --git a/tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.refout b/tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.refout new file mode 100644 index 00000000..96f0b16d --- /dev/null +++ b/tests/Al18C2_NPTNP_aeqb_ortho_c/high_accuracy/Al18C2_NPTNP_aeqb_ortho_c.refout @@ -0,0 +1,649 @@ +*************************************************************************** +* SPARC (version December 03, 2025) * +* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * +* Distributed under GNU General Public License 3 (GPL) * +* Start time: Sun Apr 5 12:40:37 2026 * +*************************************************************************** + Input parameters +*************************************************************************** +LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 +LATVEC: +1.000000000000000 0.000000000000000 0.000000000000000 +0.000000000000000 1.000000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 +FD_GRID: 126 126 126 +FD_ORDER: 12 +BC: P P P +KPOINT_GRID: 1 1 1 +KPOINT_SHIFT: 0 0 0 +SPIN_TYP: 0 +ELEC_TEMP_TYPE: Fermi-Dirac +ELEC_TEMP: 2400 +EXCHANGE_CORRELATION: GGA_PBE +HUBBARD_FLAG: 0 +NSTATES: 80 +CHEB_DEGREE: 42 +CHEFSI_BOUND_FLAG: 0 +CALC_STRESS: 1 +TWTIME: 1E+09 +MD_FLAG: 1 +MD_METHOD: NPT_NP +MD_TIMESTEP: 1 +MD_NSTEP: 10 +ION_VEL_DSTR: 2 +ION_VEL_DSTR_RAND: 0 +ION_TEMP: 2400 +NPT_SCALE_VECS: 1 2 +NPT_SCALE_CONSTRAINTS: 12 +NPT_NP_ANGLES: 0 +NPT_NP_QMASS: 20000 +NPT_NP_BMASS: 40 +TARGET_STRESS: 0.1 0.1 0.1 0 0 0 GPa +MAXIT_SCF: 100 +MINIT_SCF: 2 +MAXIT_POISSON: 3000 +TOL_SCF: 1.00E-06 +POISSON_SOLVER: AAR +TOL_POISSON: 1.00E-08 +TOL_LANCZOS: 1.00E-02 +TOL_PSEUDOCHARGE: 1.00E-09 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +TOL_PRECOND: 2.25E-05 +PRECOND_KERKER_KTF: 1 +PRECOND_KERKER_THRESH: 0 +MIXING_PARAMETER: 1 +MIXING_HISTORY: 7 +PULAY_FREQUENCY: 1 +PULAY_RESTART: 0 +REFERENCE_CUTOFF: 0.5 +RHO_TRIGGER: 4 +NUM_CHEFSI: 1 +FIX_RAND: 0 +VERBOSITY: 1 +PRINT_FORCES: 1 +PRINT_ATOMS: 1 +PRINT_EIGEN: 0 +PRINT_DENSITY: 0 +PRINT_MDOUT: 1 +PRINT_VELS: 1 +PRINT_RESTART: 1 +PRINT_RESTART_FQ: 1 +PRINT_ENERGY_DENSITY: 0 +OUTPUT_FILE: Al18C2_NPTNP_aeqb_ortho_c +*************************************************************************** + Cell +*************************************************************************** +Lattice vectors (Bohr): +18.897259886000001 0.000000000000000 0.000000000000000 +0.000000000000000 18.897259886000001 0.000000000000000 +0.000000000000000 0.000000000000000 18.897259886000001 +Volume: 6.7483330373E+03 (Bohr^3) +Density: 7.5528236408E-02 (amu/Bohr^3), 8.4635982984E-01 (g/cc) +*************************************************************************** + Parallelization +*************************************************************************** +NP_SPIN_PARAL: 1 +NP_KPOINT_PARAL: 1 +NP_BAND_PARAL: 20 +NP_DOMAIN_PARAL: 1 1 3 +NP_DOMAIN_PHI_PARAL: 3 4 5 +EIG_SERIAL_MAXNS: 1500 +*************************************************************************** + Initialization +*************************************************************************** +Number of processors : 60 +Mesh spacing : 0.149978 (Bohr) +Number of symmetry adapted k-points: 1 +Output printed to : Al18C2_NPTNP_aeqb_ortho_c.out +MD output printed to : Al18C2_NPTNP_aeqb_ortho_c.aimd +Total number of atom types : 2 +Total number of atoms : 20 +Total number of electrons : 62 +Atom type 1 (valence electrons) : Al 3 +Pseudopotential : ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +Atomic mass : 26.9815385 +Pseudocharge radii of atom type 1 : 6.90 6.90 6.90 (x, y, z dir) +Number of atoms of type 1 : 18 +Atom type 2 (valence electrons) : C 4 +Pseudopotential : ../../../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 +Atomic mass : 12.011 +Pseudocharge radii of atom type 2 : 6.90 6.90 6.90 (x, y, z dir) +Number of atoms of type 2 : 2 +Estimated total memory usage : 8.98 GB +Estimated memory per processor : 153.34 MB +=================================================================== + Self Consistent Field (SCF#1) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.5861820496E+00 1.736E-01 14.083 +2 -2.6244864496E+00 5.142E-01 4.325 +3 -2.6150746774E+00 1.241E-01 4.223 +4 -2.6174340406E+00 2.737E-01 4.212 +5 -2.6157559178E+00 6.082E-02 4.207 +6 -2.6157658314E+00 5.247E-02 4.158 +7 -2.6157288087E+00 3.444E-02 4.105 +8 -2.6157105522E+00 5.104E-03 4.096 +9 -2.6157140245E+00 7.046E-03 4.065 +10 -2.6157143797E+00 1.055E-03 4.050 +11 -2.6157148701E+00 3.967E-04 4.012 +12 -2.6157149853E+00 3.712E-04 3.998 +13 -2.6157150306E+00 1.142E-04 3.918 +14 -2.6157150409E+00 1.017E-04 3.876 +15 -2.6157150417E+00 4.235E-05 3.857 +16 -2.6157150403E+00 1.414E-05 3.826 +17 -2.6157150409E+00 7.634E-06 3.804 +18 -2.6157150425E+00 3.597E-06 3.758 +19 -2.6157150423E+00 2.730E-06 3.700 +20 -2.6157150432E+00 1.029E-06 3.662 +21 -2.6157150427E+00 5.120E-07 3.627 +Total number of SCF: 21 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157150427E+00 (Ha/atom) +Total free energy : -5.2314300855E+01 (Ha) +Band structure energy : -9.0955826271E+00 (Ha) +Exchange correlation energy : -2.0462214385E+01 (Ha) +Self and correction energy : -7.6945325391E+01 (Ha) +-Entropy*kb*T : -1.4408986085E-01 (Ha) +Fermi level : -2.8343956785E-02 (Ha) +RMS force : 1.0663907521E-02 (Ha/Bohr) +Maximum force : 1.3273884060E-02 (Ha/Bohr) +Time for force calculation : 0.165 (sec) +Pressure : -5.4252943812E+00 (GPa) +Maximum stress : 5.7978462213E+00 (GPa) +Time for stress calculation : 0.298 (sec) +MD step time : 95.267 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8972551839255 18.8972551839255 18.897259886 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149978 (Bohr) +Mesh spacing in y-direction : 0.149978 (Bohr) +Mesh spacing in z direction : 0.149978 (Bohr) +=================================================================== + Self Consistent Field (SCF#2) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159363854E+00 3.748E-02 4.359 +2 -2.6164990158E+00 1.869E-01 4.221 +3 -2.6157851525E+00 5.301E-02 4.217 +4 -2.6159181140E+00 9.179E-02 4.209 +5 -2.6157281449E+00 3.535E-03 4.171 +6 -2.6157270274E+00 2.084E-03 4.094 +7 -2.6157271183E+00 1.029E-03 4.111 +8 -2.6157274032E+00 5.649E-04 4.061 +9 -2.6157276183E+00 3.361E-04 4.053 +10 -2.6157277551E+00 1.553E-04 4.031 +11 -2.6157278025E+00 9.756E-05 3.921 +12 -2.6157278099E+00 7.211E-05 3.858 +13 -2.6157278109E+00 5.130E-05 3.876 +14 -2.6157278117E+00 1.400E-05 3.851 +15 -2.6157278121E+00 7.935E-06 3.818 +16 -2.6157278119E+00 3.322E-06 3.783 +17 -2.6157278133E+00 1.990E-06 3.742 +18 -2.6157278152E+00 9.279E-07 3.688 +Total number of SCF: 18 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157278152E+00 (Ha/atom) +Total free energy : -5.2314556304E+01 (Ha) +Band structure energy : -9.0965347290E+00 (Ha) +Exchange correlation energy : -2.0462554859E+01 (Ha) +Self and correction energy : -7.6945325713E+01 (Ha) +-Entropy*kb*T : -1.4399143495E-01 (Ha) +Fermi level : -2.8372271189E-02 (Ha) +RMS force : 1.0677469365E-02 (Ha/Bohr) +Maximum force : 1.3505967312E-02 (Ha/Bohr) +Time for force calculation : 0.163 (sec) +Pressure : -5.4244878899E+00 (GPa) +Maximum stress : 5.8009798024E+00 (GPa) +Time for stress calculation : 0.297 (sec) +MD step time : 73.431 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.897245782335 18.897245782335 18.897259886 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149978 (Bohr) +Mesh spacing in y-direction : 0.149978 (Bohr) +Mesh spacing in z direction : 0.149978 (Bohr) +=================================================================== + Self Consistent Field (SCF#3) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159707150E+00 3.812E-02 4.340 +2 -2.6165630991E+00 1.897E-01 4.215 +3 -2.6158180027E+00 5.400E-02 4.195 +4 -2.6159528371E+00 9.268E-02 4.194 +5 -2.6157590523E+00 3.581E-03 4.171 +6 -2.6157578714E+00 2.163E-03 4.102 +7 -2.6157579473E+00 1.044E-03 4.095 +8 -2.6157582423E+00 5.766E-04 4.056 +9 -2.6157584683E+00 3.497E-04 4.053 +10 -2.6157586137E+00 1.602E-04 4.020 +11 -2.6157586643E+00 1.033E-04 3.915 +12 -2.6157586726E+00 7.529E-05 3.860 +13 -2.6157586732E+00 5.392E-05 3.848 +14 -2.6157586742E+00 1.414E-05 3.872 +15 -2.6157586746E+00 8.056E-06 3.825 +16 -2.6157586746E+00 3.342E-06 3.770 +17 -2.6157586758E+00 1.961E-06 3.738 +18 -2.6157586774E+00 8.602E-07 3.685 +Total number of SCF: 18 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157586774E+00 (Ha/atom) +Total free energy : -5.2315173548E+01 (Ha) +Band structure energy : -9.0978379267E+00 (Ha) +Exchange correlation energy : -2.0463519718E+01 (Ha) +Self and correction energy : -7.6945326809E+01 (Ha) +-Entropy*kb*T : -1.4383600139E-01 (Ha) +Fermi level : -2.8414180051E-02 (Ha) +RMS force : 1.0736127499E-02 (Ha/Bohr) +Maximum force : 1.3774594007E-02 (Ha/Bohr) +Time for force calculation : 0.163 (sec) +Pressure : -5.4221072216E+00 (GPa) +Maximum stress : 5.8035224174E+00 (GPa) +Time for stress calculation : 0.296 (sec) +MD step time : 73.336 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8972316853558 18.8972316853558 18.897259886 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149978 (Bohr) +Mesh spacing in y-direction : 0.149978 (Bohr) +Mesh spacing in z direction : 0.149978 (Bohr) +=================================================================== + Self Consistent Field (SCF#4) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6156905593E+00 3.545E-03 4.046 +2 -2.6158066928E+00 4.956E-03 3.999 +3 -2.6158088653E+00 9.628E-03 4.051 +4 -2.6158068621E+00 3.336E-04 3.905 +5 -2.6158069144E+00 1.521E-03 3.871 +6 -2.6158068777E+00 3.267E-04 3.886 +7 -2.6158068735E+00 4.469E-05 3.851 +8 -2.6158068738E+00 3.420E-05 3.873 +9 -2.6158068748E+00 2.036E-05 3.857 +10 -2.6158068748E+00 8.862E-06 3.816 +11 -2.6158068758E+00 5.285E-06 3.809 +12 -2.6158068774E+00 2.153E-06 3.713 +13 -2.6158068767E+00 7.954E-07 3.663 +Total number of SCF: 13 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6158068767E+00 (Ha/atom) +Total free energy : -5.2316137533E+01 (Ha) +Band structure energy : -9.0994560135E+00 (Ha) +Exchange correlation energy : -2.0465119377E+01 (Ha) +Self and correction energy : -7.6945327848E+01 (Ha) +-Entropy*kb*T : -1.4362167729E-01 (Ha) +Fermi level : -2.8469615442E-02 (Ha) +RMS force : 1.0847694344E-02 (Ha/Bohr) +Maximum force : 1.4075277692E-02 (Ha/Bohr) +Time for force calculation : 0.163 (sec) +Pressure : -5.4182034977E+00 (GPa) +Maximum stress : 5.8055169880E+00 (GPa) +Time for stress calculation : 0.296 (sec) +MD step time : 51.631 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8972128956708 18.8972128956708 18.897259886 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149978 (Bohr) +Mesh spacing in y-direction : 0.149978 (Bohr) +Mesh spacing in z direction : 0.149978 (Bohr) +=================================================================== + Self Consistent Field (SCF#5) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6157579211E+00 3.488E-03 4.022 +2 -2.6158712955E+00 2.779E-03 4.008 +3 -2.6158759768E+00 1.534E-02 4.003 +4 -2.6158720405E+00 2.209E-03 3.896 +5 -2.6158719585E+00 9.670E-04 3.876 +6 -2.6158719455E+00 1.057E-04 3.884 +7 -2.6158719424E+00 5.301E-05 3.840 +8 -2.6158719428E+00 3.334E-05 3.849 +9 -2.6158719438E+00 1.924E-05 3.858 +10 -2.6158719440E+00 9.152E-06 3.814 +11 -2.6158719451E+00 3.982E-06 3.806 +12 -2.6158719467E+00 4.055E-06 3.680 +13 -2.6158719461E+00 5.116E-06 3.658 +14 -2.6158719468E+00 1.134E-06 3.683 +15 -2.6158719472E+00 9.310E-07 3.623 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6158719472E+00 (Ha/atom) +Total free energy : -5.2317438945E+01 (Ha) +Band structure energy : -9.1013512344E+00 (Ha) +Exchange correlation energy : -2.0467363937E+01 (Ha) +Self and correction energy : -7.6945328245E+01 (Ha) +-Entropy*kb*T : -1.4334604152E-01 (Ha) +Fermi level : -2.8537305459E-02 (Ha) +RMS force : 1.1008712454E-02 (Ha/Bohr) +Maximum force : 1.4402466837E-02 (Ha/Bohr) +Time for force calculation : 0.163 (sec) +Pressure : -5.4127761315E+00 (GPa) +Maximum stress : 5.8069574759E+00 (GPa) +Time for stress calculation : 0.296 (sec) +MD step time : 58.813 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8971894102688 18.8971894102688 18.897259886 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149978 (Bohr) +Mesh spacing in y-direction : 0.149978 (Bohr) +Mesh spacing in z direction : 0.149978 (Bohr) +=================================================================== + Self Consistent Field (SCF#6) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6158392442E+00 3.489E-03 4.025 +2 -2.6159528962E+00 8.088E-04 3.914 +3 -2.6159536698E+00 4.308E-04 3.891 +4 -2.6159537400E+00 1.454E-03 3.863 +5 -2.6159537046E+00 5.064E-04 3.876 +6 -2.6159537221E+00 9.842E-04 3.869 +7 -2.6159537025E+00 5.055E-05 3.839 +8 -2.6159537003E+00 3.244E-05 3.866 +9 -2.6159537010E+00 2.167E-05 3.860 +10 -2.6159537016E+00 1.258E-05 3.831 +11 -2.6159537018E+00 4.500E-06 3.784 +12 -2.6159537040E+00 2.530E-06 3.723 +13 -2.6159537020E+00 1.063E-06 3.649 +14 -2.6159537050E+00 8.933E-07 3.658 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6159537050E+00 (Ha/atom) +Total free energy : -5.2319074100E+01 (Ha) +Band structure energy : -9.1035720653E+00 (Ha) +Exchange correlation energy : -2.0470245646E+01 (Ha) +Self and correction energy : -7.6945328068E+01 (Ha) +-Entropy*kb*T : -1.4300652409E-01 (Ha) +Fermi level : -2.8617258241E-02 (Ha) +RMS force : 1.1205508232E-02 (Ha/Bohr) +Maximum force : 1.4751632573E-02 (Ha/Bohr) +Time for force calculation : 0.163 (sec) +Pressure : -5.4058094408E+00 (GPa) +Maximum stress : 5.8078033933E+00 (GPa) +Time for stress calculation : 0.296 (sec) +MD step time : 54.963 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8971612153416 18.8971612153416 18.897259886 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149977 (Bohr) +Mesh spacing in y-direction : 0.149977 (Bohr) +Mesh spacing in z direction : 0.149978 (Bohr) +=================================================================== + Self Consistent Field (SCF#7) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159383306E+00 3.495E-03 4.017 +2 -2.6160530553E+00 1.679E-03 3.987 +3 -2.6160554296E+00 8.501E-03 3.990 +4 -2.6160538600E+00 1.617E-03 3.866 +5 -2.6160538943E+00 1.985E-03 3.869 +6 -2.6160538308E+00 1.217E-04 3.868 +7 -2.6160538287E+00 5.619E-05 3.827 +8 -2.6160538282E+00 4.013E-05 3.868 +9 -2.6160538306E+00 2.509E-05 3.848 +10 -2.6160538304E+00 9.889E-06 3.803 +11 -2.6160538310E+00 5.445E-06 3.776 +12 -2.6160538323E+00 2.277E-06 3.661 +13 -2.6160538341E+00 5.332E-06 3.627 +14 -2.6160538332E+00 1.642E-06 3.674 +15 -2.6160538332E+00 4.547E-07 3.616 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6160538332E+00 (Ha/atom) +Total free energy : -5.2321076664E+01 (Ha) +Band structure energy : -9.1061474779E+00 (Ha) +Exchange correlation energy : -2.0473769123E+01 (Ha) +Self and correction energy : -7.6945327758E+01 (Ha) +-Entropy*kb*T : -1.4260082685E-01 (Ha) +Fermi level : -2.8709602390E-02 (Ha) +RMS force : 1.1427496537E-02 (Ha/Bohr) +Maximum force : 1.5117765203E-02 (Ha/Bohr) +Time for force calculation : 0.163 (sec) +Pressure : -5.3974202690E+00 (GPa) +Maximum stress : 5.8081699124E+00 (GPa) +Time for stress calculation : 0.297 (sec) +MD step time : 58.611 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8971282806436 18.8971282806436 18.897259886 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149977 (Bohr) +Mesh spacing in y-direction : 0.149977 (Bohr) +Mesh spacing in z direction : 0.149978 (Bohr) +=================================================================== + Self Consistent Field (SCF#8) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6160567871E+00 3.495E-03 4.009 +2 -2.6161719679E+00 1.689E-03 3.966 +3 -2.6161752011E+00 1.202E-02 3.948 +4 -2.6161727795E+00 5.531E-04 3.866 +5 -2.6161727881E+00 3.259E-04 3.850 +6 -2.6161728100E+00 9.071E-04 3.868 +7 -2.6161727871E+00 7.570E-05 3.823 +8 -2.6161727867E+00 4.203E-05 3.838 +9 -2.6161727872E+00 2.076E-05 3.839 +10 -2.6161727876E+00 1.383E-05 3.813 +11 -2.6161727882E+00 7.226E-06 3.775 +12 -2.6161727900E+00 2.780E-06 3.716 +13 -2.6161727879E+00 8.274E-07 3.644 +Total number of SCF: 13 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6161727879E+00 (Ha/atom) +Total free energy : -5.2323455759E+01 (Ha) +Band structure energy : -9.1090752655E+00 (Ha) +Exchange correlation energy : -2.0477940436E+01 (Ha) +Self and correction energy : -7.6945327695E+01 (Ha) +-Entropy*kb*T : -1.4212829784E-01 (Ha) +Fermi level : -2.8813622584E-02 (Ha) +RMS force : 1.1667635149E-02 (Ha/Bohr) +Maximum force : 1.5525855513E-02 (Ha/Bohr) +Time for force calculation : 0.163 (sec) +Pressure : -5.3876191900E+00 (GPa) +Maximum stress : 5.8080953786E+00 (GPa) +Time for stress calculation : 0.296 (sec) +MD step time : 51.257 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8970905540027 18.8970905540027 18.897259886 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149977 (Bohr) +Mesh spacing in y-direction : 0.149977 (Bohr) +Mesh spacing in z direction : 0.149978 (Bohr) +=================================================================== + Self Consistent Field (SCF#9) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6161933960E+00 3.509E-03 4.007 +2 -2.6163090986E+00 2.269E-03 3.998 +3 -2.6163128039E+00 1.249E-02 3.989 +4 -2.6163100331E+00 2.836E-03 3.883 +5 -2.6163099034E+00 1.075E-03 3.864 +6 -2.6163098888E+00 1.181E-04 3.853 +7 -2.6163098867E+00 5.843E-05 3.829 +8 -2.6163098866E+00 3.742E-05 3.858 +9 -2.6163098888E+00 2.221E-05 3.851 +10 -2.6163098884E+00 9.515E-06 3.801 +11 -2.6163098895E+00 4.440E-06 3.787 +12 -2.6163098910E+00 2.151E-06 3.688 +13 -2.6163098905E+00 1.076E-06 3.629 +14 -2.6163098927E+00 1.902E-06 3.638 +15 -2.6163098940E+00 8.336E-07 3.603 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6163098940E+00 (Ha/atom) +Total free energy : -5.2326197880E+01 (Ha) +Band structure energy : -9.1123412398E+00 (Ha) +Exchange correlation energy : -2.0482757882E+01 (Ha) +Self and correction energy : -7.6945327924E+01 (Ha) +-Entropy*kb*T : -1.4158915269E-01 (Ha) +Fermi level : -2.8928058950E-02 (Ha) +RMS force : 1.1920399423E-02 (Ha/Bohr) +Maximum force : 1.6266796643E-02 (Ha/Bohr) +Time for force calculation : 0.163 (sec) +Pressure : -5.3763861637E+00 (GPa) +Maximum stress : 5.8075508345E+00 (GPa) +Time for stress calculation : 0.296 (sec) +MD step time : 58.582 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8970479564068 18.8970479564068 18.897259886 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149977 (Bohr) +Mesh spacing in y-direction : 0.149977 (Bohr) +Mesh spacing in z direction : 0.149978 (Bohr) +=================================================================== + Self Consistent Field (SCF#10) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6163469876E+00 3.529E-03 4.012 +2 -2.6164635568E+00 2.638E-03 3.992 +3 -2.6164675111E+00 1.296E-02 3.997 +4 -2.6164645474E+00 3.354E-03 3.886 +5 -2.6164643504E+00 9.917E-04 3.874 +6 -2.6164643407E+00 1.205E-04 3.863 +7 -2.6164643392E+00 5.961E-05 3.800 +8 -2.6164643396E+00 3.811E-05 3.846 +9 -2.6164643414E+00 2.152E-05 3.841 +10 -2.6164643411E+00 9.567E-06 3.797 +11 -2.6164643418E+00 4.590E-06 3.784 +12 -2.6164643434E+00 2.137E-06 3.685 +13 -2.6164643423E+00 9.323E-07 3.645 +Total number of SCF: 13 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6164643423E+00 (Ha/atom) +Total free energy : -5.2329286846E+01 (Ha) +Band structure energy : -9.1159813129E+00 (Ha) +Exchange correlation energy : -2.0488205633E+01 (Ha) +Self and correction energy : -7.6945328427E+01 (Ha) +-Entropy*kb*T : -1.4098494909E-01 (Ha) +Fermi level : -2.9052718626E-02 (Ha) +RMS force : 1.2181488892E-02 (Ha/Bohr) +Maximum force : 1.7054769095E-02 (Ha/Bohr) +Time for force calculation : 0.164 (sec) +Pressure : -5.3637208529E+00 (GPa) +Maximum stress : 5.8065524690E+00 (GPa) +Time for stress calculation : 0.297 (sec) +MD step time : 51.370 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.897000378153 18.897000378153 18.897259886 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149976 (Bohr) +Mesh spacing in y-direction : 0.149976 (Bohr) +Mesh spacing in z direction : 0.149978 (Bohr) +=================================================================== + Self Consistent Field (SCF#11) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6165179478E+00 3.524E-03 4.011 +2 -2.6166348958E+00 1.864E-03 3.998 +3 -2.6166382639E+00 1.178E-02 3.970 +4 -2.6166358436E+00 1.741E-03 3.886 +5 -2.6166358489E+00 1.614E-03 3.871 +6 -2.6166358005E+00 1.415E-04 3.872 +7 -2.6166357980E+00 5.445E-05 3.829 +8 -2.6166357977E+00 3.771E-05 3.867 +9 -2.6166357996E+00 2.432E-05 3.856 +10 -2.6166357998E+00 1.044E-05 3.810 +11 -2.6166357999E+00 4.652E-06 3.787 +12 -2.6166358013E+00 5.225E-06 3.620 +13 -2.6166358005E+00 6.682E-06 3.673 +14 -2.6166358020E+00 9.933E-07 3.687 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6166358020E+00 (Ha/atom) +Total free energy : -5.2332716040E+01 (Ha) +Band structure energy : -9.1200097624E+00 (Ha) +Exchange correlation energy : -2.0494273404E+01 (Ha) +Self and correction energy : -7.6945329303E+01 (Ha) +-Entropy*kb*T : -1.4031526025E-01 (Ha) +Fermi level : -2.9186872329E-02 (Ha) +RMS force : 1.2447579701E-02 (Ha/Bohr) +Maximum force : 1.7888952833E-02 (Ha/Bohr) +Time for force calculation : 0.163 (sec) +Pressure : -5.3496800486E+00 (GPa) +Maximum stress : 5.8051497660E+00 (GPa) +Time for stress calculation : 0.296 (sec) +*************************************************************************** + Timing info +*************************************************************************** +Total walltime : 682.463 sec +___________________________________________________________________________ + +*************************************************************************** +* Material Physics & Mechanics Group, Georgia Tech * +* PI: Phanish Suryanarayana * +* List of contributors: See the documentation * +* Citation: See README.md or the documentation for details * +* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * +* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * +*************************************************************************** + diff --git a/tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.inpt b/tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.inpt similarity index 88% rename from tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.inpt rename to tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.inpt index c3698ab7..85406ecf 100644 --- a/tests/Al18C2_NPTNP_aeqb_c/standard/Al18C2_NPTNP_aeqb_c.inpt +++ b/tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.inpt @@ -1,10 +1,10 @@ # nprocs: 48 LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 LATVEC: -1.0 0.0 0.0 +1 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 -MESH_SPACING: 0.30 +MESH_SPACING: 0.3 BC: P P P KPOINT_GRID: 1 1 1 EXCHANGE_CORRELATION: GGA_PBE @@ -27,12 +27,15 @@ MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whicheve #TWTIME: 1400 RESTART_FLAG: 0 # 1 = restart MD from .restart file if present, 0 = start new #ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) -TARGET_PRESSURE: 0.1 GPa +EXTERNAL_PRESSURE: 0.1 GPa +#EXTERNAL_STRESS: 0 0 0 0 0 0 NPT_NP_QMASS: 20000 -NPT_NP_BMASS: 400 +NPT_NP_BMASS: 40 +#NPT_NP_ANGLES: 1 +NPT_SCALE_VECS: 1 2 NPT_SCALE_CONSTRAINTS: 12 -NSTATES: 72 +NSTATES: 80 # outputs # CALC_PRES: 1 diff --git a/tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.ion b/tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.ion similarity index 100% rename from tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.ion rename to tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.ion diff --git a/tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.refaimd b/tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.refaimd new file mode 100644 index 00000000..0649c5da --- /dev/null +++ b/tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.refaimd @@ -0,0 +1,1168 @@ +:Description: + +:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr +:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu + where atu is the atomic unit of time, hbar/Ha +:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr +:Desc_MDTM: MD time. Unit=second +:Desc_TEL: Electronic temperature. Unit=Kelvin +:Desc_TIO: Ionic temperature. Unit=Kelvin +:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom +:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom +:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom + where N = number of particles, k = Boltzmann constant +:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom +:Desc_UEN: Internal energy. Unit=Ha/atom +:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom +:Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree +:Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 +:Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 +:Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during NPT_NP ensemble (has same magnitude as initial LatVec). Unit = Bohr +:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha +:Desc_SNOSE[0]: Position variable of the thermostat +:Desc_SNOSE[1]: Velocity variable of the thermostat +:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa +:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa +:Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa +:Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa +:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa + where N = number of particles, k = Boltzmann constant, V = volume +:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr + + + + +:MDSTEP: 1 +:MDTM: 8.84 +:TWIST: 0 +:TEL: 2400 +:TIO: 2400.3419299003 +:TEN: -2.6049214949E+00 +:KEN: 1.0832038576E-02 +:KENIG: 1.1402145870E-02 +:FEN: -2.6157535335E+00 +:UEN: -2.6085495639E+00 +:TSEN: -7.2039695569E-03 +:NPT_NP_HAMIL: 3.0927340347E-05 +:SNOSE[0]: 1.0000000000E+00 +:SNOSE[1]: 0.0000000000E+00 +:R: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 6.2990803296E+00 + 0.0000000000E+00 0.0000000000E+00 1.2598160659E+01 + 0.0000000000E+00 6.2990803296E+00 0.0000000000E+00 + 0.0000000000E+00 6.2990803296E+00 6.2990803296E+00 + 0.0000000000E+00 6.2990803296E+00 1.2598160659E+01 + 0.0000000000E+00 1.2598160659E+01 0.0000000000E+00 + 0.0000000000E+00 1.2598160659E+01 6.2990803296E+00 + 0.0000000000E+00 1.2598160659E+01 1.2598160659E+01 + 6.2990803296E+00 0.0000000000E+00 0.0000000000E+00 + 6.2990803296E+00 0.0000000000E+00 6.2990803296E+00 + 6.2990803296E+00 0.0000000000E+00 1.2598160659E+01 + 6.2990803296E+00 6.2990803296E+00 0.0000000000E+00 + 6.2990803296E+00 6.2990803296E+00 6.2990803296E+00 + 6.2990803296E+00 6.2990803296E+00 1.2598160659E+01 + 6.2990803296E+00 1.2598160659E+01 0.0000000000E+00 + 6.2990803296E+00 1.2598160659E+01 6.2990803296E+00 + 6.2990803296E+00 1.2598160659E+01 1.2598160659E+01 + 1.2598160659E+01 0.0000000000E+00 0.0000000000E+00 + 1.2598160659E+01 0.0000000000E+00 6.2990803296E+00 +:V: + -6.7307827907E-06 6.8757513029E-04 4.3936347525E-04 + 3.7374966987E-05 -1.5727033900E-04 5.1719412539E-04 + 6.4987143999E-04 -4.5410616613E-04 -3.0784967305E-04 + -3.2393699965E-04 -1.3629757752E-04 -4.4900404242E-04 + 2.9185252349E-04 4.0511627087E-04 -3.3972500548E-05 + -1.6698658401E-04 3.6969237914E-04 -5.9863037015E-05 + -7.8894796912E-04 -5.9299476212E-04 2.6594883751E-04 + 4.8094590305E-05 1.3107006336E-04 3.9308996727E-04 + 4.6024249538E-04 -4.7428052205E-04 1.4680550546E-04 + -4.4621946992E-04 -2.7196354189E-05 -6.1810765568E-04 + 2.1168477813E-05 1.9314819403E-05 -3.0796199840E-04 + 9.2711056527E-05 -4.7512761344E-04 4.3477917266E-04 + 5.4429339947E-04 -4.6901437412E-05 3.8053203075E-04 + 7.8082970918E-04 3.4892980238E-04 -5.1048318450E-05 + -7.0230609303E-04 5.7124918040E-04 -2.9842620109E-04 + 5.5670641938E-05 -8.3790409042E-04 -5.9250032351E-05 + -3.2643132728E-04 5.9659835278E-04 -2.8120473491E-05 + -1.4749181903E-04 9.7048757825E-06 -4.3002557935E-04 + 1.9866356104E-04 1.8287977388E-04 2.9480623541E-04 + -3.6278179878E-04 -4.1742834911E-05 -1.4673148570E-04 +:F: + -3.1389050730E-03 1.9725289021E-07 3.3096302061E-04 + -3.1408925714E-03 1.8502172019E-07 -3.3168113612E-04 + 1.1745597854E-02 1.5972088260E-07 2.6624973177E-07 + 1.2531320424E-02 -2.4390161069E-04 1.2599453403E-04 + 1.2531369422E-02 -2.4406786004E-04 -1.2548772980E-04 + 1.3289375520E-02 -5.3795786756E-05 -1.3719518874E-07 + 1.2531309755E-02 2.4370546576E-04 1.2597023407E-04 + 1.2531346636E-02 2.4388460620E-04 -1.2546067871E-04 + 1.3289345541E-02 5.3626792330E-05 -1.4123783148E-07 + 3.1776661689E-03 1.8113757952E-07 3.3177398523E-04 + 3.1753603386E-03 1.7583127949E-07 -3.3261509347E-04 + -1.1745064500E-02 1.5664406953E-07 2.7299871796E-07 + -1.2529691639E-02 -2.4429014777E-04 1.2570098244E-04 + -1.2529604688E-02 -2.4438775986E-04 -1.2516885108E-04 + -1.3287240072E-02 -5.3624123093E-05 -1.4868180082E-07 + -1.2529686826E-02 2.4411334201E-04 1.2567934551E-04 + -1.2529586745E-02 2.4421123485E-04 -1.2514768892E-04 + -1.3287216837E-02 5.3450994763E-05 -1.4891695052E-07 + -4.4886964525E-05 4.5070494283E-09 1.1874467056E-02 + -3.9915742659E-05 1.4736825815E-08 -1.1874951197E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483330373E+03 +:LATVEC_SCALE: + 1.8897259886E+01 1.8897259886E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0617641212E-01 -7.6076919325E-02 1.3809700151E-01 + -7.6076919325E-02 7.2214981386E-01 -2.9244202651E-02 + 1.3809700151E-01 -2.9244202651E-02 4.6067110250E-01 +:STRESS: + 4.9784422294E+00 2.9485666569E-08 3.6305960185E-06 + 2.9485666569E-08 5.5537464724E+00 -2.6311522063E-07 + 3.6305960185E-06 -2.6311522063E-07 5.8252493517E+00 +:CONSTRESS: + 2.7990852252E-01 -7.4793817131E-02 1.3794330701E-01 + -7.4793817131E-02 -2.7990852252E-01 -2.9489366960E-02 + 1.3794330701E-01 -2.9489366960E-02 -5.4654728392E+00 +:TOTSTRESS: + -4.5521743398E+00 -1.2831316793E-03 1.5006390331E-04 + -1.2831316793E-03 -4.5516881360E+00 2.4542742363E-04 + 1.5006390331E-04 2.4542742363E-04 1.0089459004E-01 +:PRESIO: 6.2966577616E-01 +:PRES: -5.4524793512E+00 +:CONPRES: -1.8218242797E+00 +:TOTPRES: -3.0009892953E+00 +:PRESIG: 6.6280608016E-01 +:MIND: +Al - Al: 6.2990803296E+00 +C - C: 6.2990803296E+00 +Al - C: 6.2990803296E+00 + + +:MDSTEP: 2 +:MDTM: 6.16 +:TWIST: 0 +:TEL: 2400 +:TIO: 2403.20072678216 +:TEN: -2.6049121732E+00 +:KEN: 1.0844939488E-02 +:KENIG: 1.1415725776E-02 +:FEN: -2.6157571127E+00 +:UEN: -2.6085580323E+00 +:TSEN: -7.1990804556E-03 +:NPT_NP_HAMIL: 2.1948968642E-04 +:SNOSE[0]: 1.0000037050E+00 +:SNOSE[1]: 2.4991842213E-07 +:R: + 1.8896922360E+01 2.8425243813E-02 1.8169606127E-02 + 1.4905578063E-03 1.8890753401E+01 6.3204560426E+00 + 2.7070595106E-02 1.8878481826E+01 1.2585433759E+01 + 1.8884080909E+01 6.2934397982E+00 1.8878699666E+01 + 1.2283284921E-02 6.3158225403E+00 6.2976736821E+00 + 1.8890582612E+01 6.3143613769E+00 1.2595685841E+01 + 1.8864856758E+01 1.2573646574E+01 1.0996858481E-02 + 2.2060179959E-03 1.2603580348E+01 6.3153289988E+00 + 1.9257912425E-02 1.2578551071E+01 1.2604229787E+01 + 6.2806866765E+00 1.8896130827E+01 1.8871712278E+01 + 6.3000090554E+00 7.9850253578E-04 6.2863430022E+00 + 6.3027074829E+00 1.8877612772E+01 1.2616134999E+01 + 6.3213628454E+00 6.2971355429E+00 1.5733871598E-02 + 6.3311415622E+00 6.3134997138E+00 6.2969677512E+00 + 6.2698136567E+00 6.3226939973E+00 1.2585823330E+01 + 6.3011625521E+00 1.2563521714E+01 1.8894812596E+01 + 6.2853659669E+00 1.2622825893E+01 6.2979156184E+00 + 6.2927503929E+00 1.2598559647E+01 1.2580382841E+01 + 1.2606368761E+01 7.5604852854E-03 1.2651133770E-02 + 1.2583158082E+01 1.8895529454E+01 6.2925507791E+00 +:V: + -9.3954255205E-06 6.8789451018E-04 4.3971101504E-04 + 3.4854653703E-05 -1.5741745463E-04 5.1704826107E-04 + 6.5974586998E-04 -4.5424632751E-04 -3.0803372187E-04 + -3.1349534260E-04 -1.3659782299E-04 -4.4896760503E-04 + 3.0233352528E-04 4.0502231395E-04 -3.3981490056E-05 + -1.5572483677E-04 3.6991348182E-04 -5.9833745217E-05 + -7.7854221558E-04 -5.9303080983E-04 2.6605445047E-04 + 5.8713406307E-05 1.3131611939E-04 3.9300158559E-04 + 4.7147903167E-04 -4.7432947333E-04 1.4675866382E-04 + -4.4388153983E-04 -2.7033087536E-05 -6.1805847319E-04 + 2.4012548400E-05 1.9167058497E-05 -3.0829856184E-04 + 8.2841391558E-05 -4.7534636239E-04 4.3504080367E-04 + 5.3384714849E-04 -4.7000197472E-05 3.8076514169E-04 + 7.7036490611E-04 3.4867311552E-04 -5.1145986802E-05 + -7.1356179707E-04 5.7145043460E-04 -2.9860850489E-04 + 4.5237471380E-05 -8.3793966343E-04 -5.9082717478E-05 + -3.3704267903E-04 5.9695939631E-04 -2.8157731984E-05 + -1.5874136445E-04 9.7170761520E-06 -4.3013622840E-04 + 1.9923280228E-04 1.8281980028E-04 3.1751658880E-04 + -3.6332070415E-04 -4.1683524411E-05 -1.6942286181E-04 +:F: + -3.2014769798E-03 7.6539507821E-04 4.9985619658E-04 + -2.8557059244E-03 -3.5152834151E-04 -1.0833735259E-05 + 1.1755244308E-02 -3.3739599346E-04 -4.4091043750E-04 + 1.2311193395E-02 -4.7163100953E-04 -4.3252367649E-05 + 1.2409824180E-02 2.3833792590E-05 1.0379791481E-04 + 1.3505773697E-02 5.8293166052E-04 6.9307074330E-05 + 1.2221951876E-02 -3.3435200420E-04 1.2767284287E-04 + 1.2735761708E-02 3.4266537637E-04 -8.1371919573E-05 + 1.3450972104E-02 -1.7400118270E-04 -1.1002070782E-04 + 2.3816046282E-03 3.8807595738E-04 -2.2019584545E-04 + 3.5920755392E-03 -3.5160296109E-04 -4.7092831864E-04 + -1.1738335437E-02 -5.2455889827E-04 6.2609111234E-04 + -1.2321941692E-02 8.9116661536E-06 4.3232401047E-04 + -1.2364227556E-02 -3.6351175753E-04 -1.0767610073E-04 + -1.3500675600E-02 5.3718891532E-04 -4.3626028532E-04 + -1.2294839240E-02 -3.3564354979E-04 2.7191187445E-04 + -1.2722048963E-02 6.1976957086E-04 3.6245555699E-05 + -1.3481484129E-02 -2.4341177065E-05 -2.6692312797E-04 + 6.4856297953E-04 -6.2860262514E-05 1.2181894261E-02 + -5.3222889262E-04 6.2655120269E-05 -1.2160727997E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483296594E+03 +:LATVEC_SCALE: + 1.8897255156E+01 1.8897255156E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0585218057E-01 -7.8708462750E-02 1.3856098239E-01 + -7.8708462750E-02 7.2250792707E-01 -2.8778410117E-02 + 1.3856098239E-01 -2.8778410117E-02 4.6288795517E-01 +:STRESS: + 4.9701622961E+00 -1.6006536324E-03 1.5840792196E-03 + -1.6006536324E-03 5.5552024732E+00 6.0994305764E-04 + 1.5840792196E-03 6.0994305764E-04 5.8275462109E+00 +:CONSTRESS: + 5.6388444466E-01 -1.5311869539E-01 1.3666198639E-01 + -1.5311869539E-01 -5.6388444466E-01 -2.9608510683E-02 + 1.3666198639E-01 -2.9608510683E-02 -5.4659329435E+00 +:TOTSTRESS: + -4.8281945602E+00 7.6010886273E-02 3.1491678248E-04 + 7.6010886273E-02 -4.2688101015E+00 2.2015750813E-04 + 3.1491678248E-04 2.2015750813E-04 1.0127468781E-01 +:PRESIO: 6.3041602094E-01 +:PRES: -5.4509703268E+00 +:CONPRES: -1.8219776478E+00 +:TOTPRES: -2.9985766580E+00 +:PRESIG: 6.6359581152E-01 +:MIND: +Al - Al: 6.2556434470E+00 +C - C: 6.2799494046E+00 +Al - C: 6.2831526002E+00 + + +:MDSTEP: 3 +:MDTM: 6.21 +:TWIST: 0 +:TEL: 2400 +:TIO: 2409.75099295597 +:TEN: -2.6049050941E+00 +:KEN: 1.0874498916E-02 +:KENIG: 1.1446840964E-02 +:FEN: -2.6157795931E+00 +:UEN: -2.6085884999E+00 +:TSEN: -7.1910931480E-03 +:NPT_NP_HAMIL: 3.7750030053E-04 +:SNOSE[0]: 1.0000391073E+00 +:SNOSE[1]: 1.8956953086E-06 +:R: + 1.8896468869E+01 5.6876513882E-02 3.6356226208E-02 + 2.8818544486E-03 1.8884230106E+01 6.3418309612E+00 + 5.4549123547E-02 1.8859687692E+01 1.2572691787E+01 + 1.8871325265E+01 6.2877814160E+00 1.8860138305E+01 + 2.4997545327E-02 6.3325636680E+00 6.2962706689E+00 + 1.8884370050E+01 6.3296607983E+00 1.2593213480E+01 + 1.8832874246E+01 1.2549118211E+01 2.1997938374E-02 + 4.8545393724E-03 1.2609008685E+01 6.3315745227E+00 + 3.8982838720E-02 1.2558932679E+01 1.2610294972E+01 + 6.2623745737E+00 1.8895010550E+01 1.8846157519E+01 + 6.3010610061E+00 1.5847714111E-03 6.2735895598E+00 + 6.3059250993E+00 1.8857943099E+01 1.2634130742E+01 + 6.3432151708E+00 6.2951895294E+00 3.1482458137E-02 + 6.3627709390E+00 6.3279046020E+00 6.2948514725E+00 + 6.2400768680E+00 6.3463242826E+00 1.2573471084E+01 + 6.3028159311E+00 1.2528868650E+01 1.8892374803E+01 + 6.2712082326E+00 1.2647509016E+01 6.2967521894E+00 + 6.2859505474E+00 1.2598954630E+01 1.2562596096E+01 + 1.2614624174E+01 1.5115912154E-02 2.6252926350E-02 + 1.2568111109E+01 1.8893799222E+01 6.2850721023E+00 +:V: + -1.2108023608E-05 6.8883828924E-04 4.4018728094E-04 + 3.2577591332E-05 -1.5785424101E-04 5.1715537503E-04 + 6.6960412458E-04 -4.5465932433E-04 -3.0857706748E-04 + -3.0323449299E-04 -1.3708142984E-04 -4.4905777484E-04 + 3.1270421468E-04 4.0513925699E-04 -3.3796936215E-05 + -1.4427831480E-04 3.7065646168E-04 -5.9743402438E-05 + -7.6837331106E-04 -5.9354189810E-04 2.6615297515E-04 + 6.9502453598E-05 1.3164084596E-04 3.9293703882E-04 + 4.8283301007E-04 -4.7455275703E-04 1.4661360807E-04 + -4.4218542971E-04 -2.6540671257E-05 -6.1845358050E-04 + 2.7217642147E-05 1.8725581787E-05 -3.0874280034E-04 + 7.2977873647E-05 -4.7599215976E-04 4.3581176911E-04 + 5.2356370671E-04 -4.6884908283E-05 3.8124503956E-04 + 7.6001722508E-04 3.4830346194E-04 -5.1230316657E-05 + -7.2497235673E-04 5.7213199094E-04 -2.9914712880E-04 + 3.5000144657E-05 -8.3843874061E-04 -5.8789726497E-05 + -3.4780177793E-04 5.9761511140E-04 -2.8060452669E-05 + -1.7014629179E-04 9.6671837397E-06 -4.3045544255E-04 + 2.0105860946E-04 1.8263848977E-04 3.4083520676E-04 + -3.6481681997E-04 -4.1501643691E-05 -1.9268150784E-04 +:F: + -3.2538370076E-03 1.5374075246E-03 6.7043871368E-04 + -2.5595970247E-03 -7.0085653325E-04 3.0925586304E-04 + 1.1756924726E-02 -6.8303255581E-04 -8.7790182307E-04 + 1.2078118361E-02 -6.9043490019E-04 -2.0911964484E-04 + 1.2291986890E-02 2.8805852463E-04 3.3247527918E-04 + 1.3717899219E-02 1.2156718950E-03 1.4061916643E-04 + 1.1909961379E-02 -9.3100274761E-04 1.2917447435E-04 + 1.2941280708E-02 4.4091381898E-04 -3.9111087202E-05 + 1.3604583514E-02 -3.9668142890E-04 -2.2277032199E-04 + 1.6173829138E-03 7.8135997307E-04 -7.7200133719E-04 + 4.0363221152E-03 -6.9727806192E-04 -6.1208944365E-04 + -1.1724689829E-02 -1.0515597146E-03 1.2450301741E-03 + -1.2102828078E-02 2.6150750633E-04 7.4164529143E-04 + -1.2193754926E-02 -4.8710872558E-04 -9.7292446228E-05 + -1.3709615911E-02 1.1319966864E-03 -8.7052293806E-04 + -1.2060777999E-02 -9.2146979681E-04 4.2027087117E-04 + -1.2906846413E-02 9.9004997457E-04 1.9285266886E-04 + -1.3669330965E-02 -9.3567957301E-05 -5.2886425710E-04 + 1.2927481623E-03 -1.2243051916E-04 1.2529886685E-02 + -1.0659298365E-03 1.2845703755E-04 -1.2481975888E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483229058E+03 +:LATVEC_SCALE: + 1.8897245700E+01 1.8897245700E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0672164693E-01 -8.1467190360E-02 1.3935154619E-01 + -8.1467190360E-02 7.2382920487E-01 -2.8362877606E-02 + 1.3935154619E-01 -2.8362877606E-02 4.6585397510E-01 +:STRESS: + 4.9598601427E+00 -3.2555805376E-03 2.6264463101E-03 + -3.2555805376E-03 5.5535682966E+00 1.6880154916E-03 + 2.6264463101E-03 1.6880154916E-03 5.8287845906E+00 +:CONSTRESS: + 5.7251296908E-01 -1.5525109008E-01 1.3624101389E-01 + -1.5525109008E-01 -5.7251296908E-01 -3.0244502458E-02 + 1.3624101389E-01 -3.0244502458E-02 -5.4645913610E+00 +:TOTSTRESS: + -4.8256514648E+00 7.7039480259E-02 4.8408599123E-04 + 7.7039480259E-02 -4.2572261226E+00 1.9360936042E-04 + 4.8408599123E-04 1.9360936042E-04 1.0166074558E-01 +:PRESIO: 6.3213494230E-01 +:PRES: -5.4474043433E+00 +:CONPRES: -1.8215304537E+00 +:TOTPRES: -2.9937389473E+00 +:PRESIG: 6.6540520242E-01 +:MIND: +Al - Al: 6.2122900218E+00 +C - C: 6.2590195322E+00 +Al - C: 6.2670626420E+00 + + +:MDSTEP: 4 +:MDTM: 4.48 +:TWIST: 0 +:TEL: 2400 +:TIO: 2419.60144094906 +:TEN: -2.6049052581E+00 +:KEN: 1.0918951097E-02 +:KENIG: 1.1493632733E-02 +:FEN: -2.6158242092E+00 +:UEN: -2.6086440359E+00 +:TSEN: -7.1801732697E-03 +:NPT_NP_HAMIL: 4.4322064469E-04 +:SNOSE[0]: 1.0001937757E+00 +:SNOSE[1]: 6.3693240738E-06 +:R: + 1.8895897640E+01 8.5378478520E-02 5.4564413532E-02 + 4.1840811924E-03 1.8877678362E+01 6.3632145943E+00 + 8.2433530643E-02 1.8840866904E+01 1.2559920522E+01 + 1.8858985792E+01 6.2820980118E+00 1.8841571443E+01 + 3.8137689792E-02 6.3493116275E+00 6.2948793413E+00 + 1.8878630009E+01 6.3449994208E+00 1.2590746240E+01 + 1.8801303904E+01 1.2524556701E+01 3.3002461303E-02 + 7.9524693721E-03 1.2614448675E+01 6.3478171440E+00 + 5.9178585615E-02 1.2539299234E+01 1.2616351841E+01 + 6.2441188491E+00 1.8893912808E+01 1.8820578363E+01 + 6.3022515297E+00 2.3467371224E-03 6.2608160614E+00 + 6.3087334437E+00 1.8838234049E+01 1.2652168037E+01 + 6.3646433006E+00 6.2932512148E+00 4.7255317747E-02 + 6.3939720244E+00 6.3422896116E+00 6.2927320143E+00 + 6.2098649943E+00 6.3699900637E+00 1.2561089763E+01 + 6.3040485099E+00 1.2494183740E+01 1.8889951845E+01 + 6.2566018145E+00 1.2672221029E+01 6.2955955719E+00 + 6.2786748199E+00 1.2599343176E+01 1.2544792665E+01 + 1.2622976553E+01 2.2661059229E-02 4.0831438304E-02 + 1.2552979230E+01 1.8892074460E+01 6.2766198640E+00 +:V: + -1.4866278603E-05 6.9034914889E-04 4.4075511546E-04 + 3.0543859296E-05 -1.5856351445E-04 5.1746870981E-04 + 6.7937999535E-04 -4.5531227231E-04 -3.0944862121E-04 + -2.9313878053E-04 -1.3772950658E-04 -4.4923239655E-04 + 3.2294018784E-04 4.0542767740E-04 -3.3417351814E-05 + -1.3263962422E-04 3.7188461273E-04 -5.9584739252E-05 + -7.5837632881E-04 -5.9448836044E-04 2.6622044306E-04 + 8.0455205367E-05 1.3203204256E-04 3.9286087622E-04 + 4.9425375107E-04 -4.7490403903E-04 1.4635484357E-04 + -4.4107373683E-04 -2.5714137689E-05 -6.1923699980E-04 + 3.0796100024E-05 1.7993846035E-05 -3.0926945279E-04 + 6.3119663296E-05 -4.7702396941E-04 4.3704643287E-04 + 5.1340560224E-04 -4.6551930229E-05 3.8194029323E-04 + 7.4972345522E-04 3.4778837405E-04 -5.1303165451E-05 + -7.3646903530E-04 5.7324483463E-04 -3.0001331335E-04 + 2.4954917550E-05 -8.3933142625E-04 -5.8364418869E-05 + -3.5867102569E-04 5.9850731901E-04 -2.7830267070E-05 + -1.8168565502E-04 9.5624933486E-06 -4.3094092762E-04 + 2.0406981772E-04 1.8232618512E-04 3.6480312748E-04 + -3.6727605207E-04 -4.1187404444E-05 -2.1655194091E-04 +:F: + -3.3141564486E-03 2.3100342416E-03 8.4275132310E-04 + -2.2679796673E-03 -1.0447146295E-03 6.2663587397E-04 + 1.1751015803E-02 -1.0371934923E-03 -1.3095711523E-03 + 1.1834690660E-02 -9.0191546508E-04 -3.7164280498E-04 + 1.2180130349E-02 5.4660841286E-04 5.5833291904E-04 + 1.3924766205E-02 1.8425293897E-03 2.1494702628E-04 + 1.1597582873E-02 -1.5385106958E-03 1.2931136918E-04 + 1.3147404819E-02 5.3817910401E-04 2.4632144019E-06 + 1.3749096492E-02 -6.1299345724E-04 -3.3902817211E-04 + 8.6614201549E-04 1.1757161116E-03 -1.3197652185E-03 + 4.4889351125E-03 -1.0370824688E-03 -7.5473688617E-04 + -1.1707258549E-02 -1.5780070947E-03 1.8533084995E-03 + -1.1877764830E-02 5.1366119475E-04 1.0530521767E-03 + -1.2023076373E-02 -6.1104219155E-04 -9.4911006139E-05 + -1.3913431077E-02 1.7255999655E-03 -1.3007036198E-03 + -1.1830120466E-02 -1.5097574081E-03 5.7014975893E-04 + -1.3085045984E-02 1.3518689994E-03 3.4456152711E-04 + -1.3852116529E-02 -1.5200952078E-04 -7.8477876532E-04 + 1.9297422452E-03 -1.7861603041E-04 1.2915073459E-02 + -1.5985566500E-03 1.9764503469E-04 -1.2835449522E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483127808E+03 +:LATVEC_SCALE: + 1.8897231524E+01 1.8897231524E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0865837512E-01 -8.4338873537E-02 1.4045341593E-01 + -8.4338873537E-02 7.2599307480E-01 -2.7994729942E-02 + 1.4045341593E-01 -2.7994729942E-02 4.6950825360E-01 +:STRESS: + 4.9479722613E+00 -4.9571822671E-03 3.0557191163E-03 + -4.9571822671E-03 5.5495793534E+00 3.2331445277E-03 + 3.0557191163E-03 3.2331445277E-03 5.8295223690E+00 +:CONSTRESS: + 5.8042434807E-01 -1.5751568792E-01 1.3673966132E-01 + -1.5751568792E-01 -5.8042434807E-01 -3.1394273120E-02 + 1.3673966132E-01 -3.1394273120E-02 -5.4620668429E+00 +:TOTSTRESS: + -4.8197382342E+00 7.8133996651E-02 6.5803549802E-04 + 7.8133996651E-02 -4.2431619305E+00 1.6639865057E-04 + 6.5803549802E-04 1.6639865057E-04 1.0205272745E-01 +:PRESIO: 6.3471990118E-01 +:PRES: -5.4423579946E+00 +:CONPRES: -1.8206889476E+00 +:TOTPRES: -2.9869491458E+00 +:PRESIG: 6.6812621176E-01 +:MIND: +Al - Al: 6.1690000103E+00 +C - C: 6.2362433213E+00 +Al - C: 6.2507521826E+00 + + +:MDSTEP: 5 +:MDTM: 4.77 +:TWIST: 0 +:TEL: 2400 +:TIO: 2432.06467776664 +:TEN: -2.6049115924E+00 +:KEN: 1.0975194026E-02 +:KENIG: 1.1552835817E-02 +:FEN: -2.6158867864E+00 +:UEN: -2.6087206532E+00 +:TSEN: -7.1661332028E-03 +:NPT_NP_HAMIL: 5.0270035564E-04 +:SNOSE[0]: 1.0006141929E+00 +:SNOSE[1]: 1.4876549359E-05 +:R: + 1.8895206717E+01 1.1395247815E-01 7.2796646691E-02 + 5.4071388083E-03 1.8871087492E+01 6.3846138525E+00 + 1.1071814703E-01 1.8822010790E+01 1.2547107430E+01 + 1.8847056315E+01 6.2763833393E+00 1.8822997004E+01 + 5.1697203797E-02 6.3660721741E+00 6.2935078110E+00 + 1.8873370674E+01 6.3603960592E+00 1.2588287176E+01 + 1.8770140866E+01 1.2499945677E+01 4.4008314162E-02 + 1.1506269752E-02 1.2619902646E+01 6.3640551829E+00 + 7.9846175917E-02 1.2519647009E+01 1.2622395191E+01 + 6.2258969072E+00 1.8892851509E+01 1.8794960708E+01 + 6.3035960901E+00 3.0724530492E-03 6.2480200131E+00 + 6.3111326742E+00 1.8818471142E+01 1.2670264534E+01 + 6.3856510232E+00 6.2913297315E+00 6.3060229298E-02 + 6.4247448360E+00 6.3566476707E+00 6.2906098678E+00 + 6.1791768831E+00 6.3937073970E+00 1.2548666812E+01 + 6.3048681610E+00 1.2459453233E+01 1.8887549390E+01 + 6.2415434382E+00 1.2696969735E+01 6.2944512575E+00 + 6.2709183707E+00 1.2599723183E+01 1.2526967086E+01 + 1.2631473982E+01 3.0190090485E-02 5.6413704007E-02 + 1.2537723810E+01 1.8890360901E+01 6.2671683254E+00 +:V: + -1.7674358987E-05 6.9232392963E-04 4.4135172391E-04 + 2.8746546460E-05 -1.5951679447E-04 5.1790931674E-04 + 6.8896451794E-04 -4.5614471126E-04 -3.1059814710E-04 + -2.8317730739E-04 -1.3851410539E-04 -4.4942238350E-04 + 3.3299544448E-04 4.0582292041E-04 -3.2840712589E-05 + -1.2079683730E-04 3.7353741223E-04 -5.9346728371E-05 + -7.4844329817E-04 -5.9579166203E-04 2.6621704059E-04 + 9.1556727232E-05 1.3246921235E-04 3.9271511678E-04 + 5.0565699097E-04 -4.7530860100E-04 1.4595768830E-04 + -4.4047032502E-04 -2.4548171568E-05 -6.2031200307E-04 + 3.4748927993E-05 1.6974558644E-05 -3.0983325479E-04 + 5.3263299528E-05 -4.7837061209E-04 4.3866845659E-04 + 5.0330556869E-04 -4.5996776773E-05 3.8279507122E-04 + 7.3937698852E-04 3.4707639132E-04 -5.1363110469E-05 + -7.4793571401E-04 5.7470332634E-04 -3.0115846817E-04 + 1.5098673239E-05 -8.4049536263E-04 -5.7797653772E-05 + -3.6958881172E-04 5.9954135539E-04 -2.7466765210E-05 + -1.9332450546E-04 9.4108369318E-06 -4.3152454928E-04 + 2.0822127366E-04 1.8186293201E-04 3.8943188022E-04 + -3.7064183948E-04 -4.0728540251E-05 -2.4105843845E-04 +:F: + -3.3836746644E-03 3.0783015945E-03 1.0178266779E-03 + -1.9790777590E-03 -1.3821257990E-03 9.3935092430E-04 + 1.1737142429E-02 -1.3980767132E-03 -1.7355562749E-03 + 1.1580477362E-02 -1.1027219208E-03 -5.2968721760E-04 + 1.2072785286E-02 7.9842862390E-04 7.8056253445E-04 + 1.4127797072E-02 2.4618569160E-03 2.9190310773E-04 + 1.1285799986E-02 -2.1561602654E-03 1.2879748352E-04 + 1.3353580591E-02 6.3394231949E-04 4.3471837288E-05 + 1.3882762200E-02 -8.2353805804E-04 -4.5979885116E-04 + 1.3008482539E-04 1.5734586846E-03 -1.8577524714E-03 + 4.9491164929E-03 -1.3707231752E-03 -8.9629260006E-04 + -1.1687167947E-02 -2.1026530674E-03 2.4438844947E-03 + -1.1647430096E-02 7.6107078244E-04 1.3631097422E-03 + -1.1852854697E-02 -7.3645303190E-04 -9.9053186264E-05 + -1.4111019995E-02 2.3172251348E-03 -1.7245866066E-03 + -1.1602137254E-02 -2.0974890036E-03 7.2031541321E-04 + -1.3256208879E-02 1.7060358614E-03 4.9268548262E-04 + -1.4028660121E-02 -1.9937192995E-04 -1.0350622026E-03 + 2.5589565429E-03 -2.3119445782E-04 1.3339863504E-02 + -2.1302713770E-03 2.7018750512E-04 -1.3223981791E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7482992878E+03 +:LATVEC_SCALE: + 1.8897212632E+01 1.8897212632E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.1144986938E-01 -8.7298277046E-02 1.4183438977E-01 + -8.7298277046E-02 7.2878922285E-01 -2.7667449417E-02 + 1.4183438977E-01 -2.7667449417E-02 4.7373266238E-01 +:STRESS: + 4.9344773502E+00 -6.7342423961E-03 2.8682648655E-03 + -6.7342423961E-03 5.5431108534E+00 5.2391482820E-03 + 2.8682648655E-03 5.2391482820E-03 5.8296784218E+00 +:CONSTRESS: + 5.8769469029E-01 -1.5984628096E-01 1.3812947335E-01 + -1.5984628096E-01 -5.8769469029E-01 -3.3045054074E-02 + 1.3812947335E-01 -3.3045054074E-02 -5.4583964890E+00 +:TOTSTRESS: + -4.8107221711E+00 7.9282246312E-02 8.3665154905E-04 + 7.9282246312E-02 -4.2266269402E+00 1.3845637537E-04 + 8.3665154905E-04 1.3845637537E-04 1.0245072956E-01 +:PRESIO: 6.3799058487E-01 +:PRES: -5.4357555418E+00 +:CONPRES: -1.8194654963E+00 +:TOTPRES: -2.9782994606E+00 +:PRESIG: 6.7156903671E-01 +:MIND: +Al - Al: 6.1257408363E+00 +C - C: 6.2115725995E+00 +Al - C: 6.2341650263E+00 + + +:MDSTEP: 6 +:MDTM: 4.79 +:TWIST: 0 +:TEL: 2400 +:TIO: 2446.23574757922 +:TEN: -2.6049293890E+00 +:KEN: 1.1039143905E-02 +:KENIG: 1.1620151479E-02 +:FEN: -2.6159685329E+00 +:UEN: -2.6088197703E+00 +:TSEN: -7.1487626244E-03 +:NPT_NP_HAMIL: 5.3382538136E-04 +:SNOSE[0]: 1.0014881426E+00 +:SNOSE[1]: 2.8260496811E-05 +:R: + 1.8894393985E+01 1.4261489438E-01 9.1052448389E-02 + 6.5606632460E-03 1.8864448155E+01 6.4060319063E+00 + 1.3939212281E-01 1.8803113598E+01 1.2534242337E+01 + 1.8835532071E+01 6.2706324897E+00 1.8804416173E+01 + 6.5667271490E-02 6.3828480228E+00 6.2921642793E+00 + 1.8868600730E+01 6.3758666605E+00 1.2585839841E+01 + 1.8739385282E+01 1.2475272548E+01 5.5011526942E-02 + 1.5521590590E-02 1.2625371953E+01 6.3802842363E+00 + 1.0098258420E-01 1.2499975754E+01 1.2628418665E+01 + 6.2076897083E+00 1.8891840821E+01 1.8769295084E+01 + 6.3051101059E+00 3.7500884627E-03 6.2352011038E+00 + 6.3131228341E+00 1.8798643271E+01 1.2688434221E+01 + 6.4062390043E+00 6.2894343514E+00 7.8902271331E-02 + 6.4550844468E+00 6.3709692756E+00 6.2884856526E+00 + 6.1480169391E+00 6.4174882809E+00 1.2536191989E+01 + 6.3052827177E+00 1.2424669213E+01 1.8885173508E+01 + 6.2260327979E+00 1.2721758519E+01 6.2933247956E+00 + 6.2626780985E+00 1.2600092866E+01 1.2509117076E+01 + 1.2640162421E+01 3.7696206639E-02 7.3026758143E-02 + 1.2522308901E+01 1.8888664806E+01 6.2566910777E+00 +:V: + -2.0533843193E-05 6.9462585093E-04 4.4189518892E-04 + 2.7178941178E-05 -1.6067812957E-04 5.1837446030E-04 + 6.9821701125E-04 -4.5707552617E-04 -3.1196000689E-04 + -2.7331285806E-04 -1.3939960889E-04 -4.4953955214E-04 + 3.4280603036E-04 4.0624297149E-04 -3.2064201016E-05 + -1.0873632347E-04 3.7553627591E-04 -5.9016534270E-05 + -7.3843801558E-04 -5.9734618009E-04 2.6609234054E-04 + 1.0278246353E-04 1.3292588840E-04 3.9242643403E-04 + 5.1693113463E-04 -4.7567160496E-04 1.4539107375E-04 + -4.4028032661E-04 -2.3039145925E-05 -6.2155123818E-04 + 3.9073784735E-05 1.5670746503E-05 -3.1037509989E-04 + 4.3405868333E-05 -4.7993889999E-04 4.4057808867E-04 + 4.9318022125E-04 -4.5213139117E-05 3.8373548799E-04 + 7.2884406833E-04 3.4610198217E-04 -5.1405894463E-05 + -7.5922105119E-04 5.7639649458E-04 -3.0251960085E-04 + 5.4309643886E-06 -8.4177066774E-04 -5.7078776733E-05 + -3.8047256770E-04 6.0059745342E-04 -2.6968541821E-05 + -2.0501355087E-04 9.2189120210E-06 -4.3211985816E-04 + 2.1345413032E-04 1.8122254492E-04 4.1471051003E-04 + -3.7484005780E-04 -4.0111800944E-05 -2.6620931981E-04 +:F: + -3.4598469912E-03 3.8371186836E-03 1.1926213067E-03 + -1.6930408863E-03 -1.7131356922E-03 1.2436333527E-03 + 1.1717218159E-02 -1.7637326782E-03 -2.1513288744E-03 + 1.1314174784E-02 -1.2924279049E-03 -6.8275277684E-04 + 1.1971727350E-02 1.0431952354E-03 9.9957850279E-04 + 1.4331129939E-02 3.0709396917E-03 3.7079554282E-04 + 1.0978997666E-02 -2.7799133526E-03 1.2737555367E-04 + 1.3558683523E-02 7.2790282287E-04 8.5103796732E-05 + 1.4003755594E-02 -1.0264425744E-03 -5.8575125965E-04 + -5.9117216194E-04 1.9676257466E-03 -2.3805552189E-03 + 5.4179154788E-03 -1.6975979940E-03 -1.0371089857E-03 + -1.1667590308E-02 -2.6226730470E-03 3.0129276262E-03 + -1.1411645602E-02 1.0088275352E-03 1.6705687806E-03 + -1.1686709309E-02 -8.6308050234E-04 -1.0948526041E-04 + -1.4304680556E-02 2.9051711246E-03 -2.1409582476E-03 + -1.1380248886E-02 -2.6815451439E-03 8.7081526178E-04 + -1.3418736149E-02 2.0514675140E-03 6.3619715098E-04 + -1.4197610356E-02 -2.3795983639E-04 -1.2783541839E-03 + 3.1781856628E-03 -2.7945487133E-04 1.3807258208E-02 + -2.6605069510E-03 3.4571524323E-04 -1.3650580275E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7482824267E+03 +:LATVEC_SCALE: + 1.8897189024E+01 1.8897189024E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.1482092475E-01 -9.0309712192E-02 1.4344959579E-01 + -9.0309712192E-02 7.3194200895E-01 -2.7372165088E-02 + 1.4344959579E-01 -2.7372165088E-02 4.7836589499E-01 +:STRESS: + 4.9196385819E+00 -8.5911752973E-03 2.0695694998E-03 + -8.5911752973E-03 5.5344725442E+00 7.6176492675E-03 + 2.0695694998E-03 7.6176492675E-03 5.8293574064E+00 +:CONSTRESS: + 5.9428068555E-01 -1.6214645197E-01 1.4035953419E-01 + -1.6214645197E-01 -5.9428068555E-01 -3.5100018930E-02 + 1.4035953419E-01 -3.5100018930E-02 -5.4538461113E+00 +:TOTSTRESS: + -4.7990983427E+00 8.0427915080E-02 1.0204921007E-03 + 8.0427915080E-02 -4.2082498497E+00 1.1020457446E-04 + 1.0204921007E-03 1.1020457446E-04 1.0285459990E-01 +:PRESIO: 6.4170960956E-01 +:PRES: -5.4278228442E+00 +:CONPRES: -1.8179487038E+00 +:TOTPRES: -2.9681645308E+00 +:PRESIG: 6.7548379954E-01 +:MIND: +Al - Al: 6.0824888625E+00 +C - C: 6.1849599996E+00 +Al - C: 6.2172480512E+00 + + +:MDSTEP: 7 +:MDTM: 4.49 +:TWIST: 0 +:TEL: 2400 +:TIO: 2461.0434268633 +:TEN: -2.6049679329E+00 +:KEN: 1.1105966615E-02 +:KENIG: 1.1690491174E-02 +:FEN: -2.6160738995E+00 +:UEN: -2.6089459782E+00 +:TSEN: -7.1279213029E-03 +:NPT_NP_HAMIL: 4.4873655711E-04 +:SNOSE[0]: 1.0030334021E+00 +:SNOSE[1]: 4.7109188969E-05 +:R: + 1.8893457345E+01 1.7137592047E-01 1.0932763550E-01 + 7.6540078849E-03 1.8857752600E+01 6.4274673017E+00 + 1.6843830999E-01 1.8784173238E+01 1.2521318067E+01 + 1.8824409847E+01 6.2648421260E+00 1.8785834053E+01 + 8.0036149794E-02 6.3996382437E+00 6.2908570761E+00 + 1.8864329403E+01 6.3914236186E+00 1.2583408333E+01 + 1.8709043311E+01 1.2450529528E+01 6.6005887416E-02 + 2.0002849941E-02 1.2630856757E+01 6.3964966647E+00 + 1.2257970298E-01 1.2480289451E+01 1.2634414532E+01 + 6.1894823917E+00 1.8890894920E+01 1.8743577766E+01 + 6.3068088302E+00 4.3679608179E-03 6.2223616494E+00 + 6.3147038789E+00 1.8778743532E+01 1.2706686602E+01 + 6.4264042916E+00 6.2875747047E+00 9.4783206339E-02 + 6.4849800332E+00 6.3852420271E+00 6.2863601985E+00 + 6.1163963589E+00 6.4413397271E+00 1.2523657877E+01 + 6.3053000399E+00 1.2389830931E+01 1.8882830729E+01 + 6.2100733795E+00 1.2746585420E+01 6.2922217830E+00 + 6.2539532214E+00 1.2600450671E+01 1.2491244215E+01 + 1.2649085094E+01 4.5171457995E-02 9.0696738356E-02 + 1.2506701922E+01 1.8886992970E+01 6.2451617220E+00 +:V: + -2.3441858490E-05 6.9709253899E-04 4.4228912289E-04 + 2.5834974085E-05 -1.6200555726E-04 5.1874291396E-04 + 7.0697346476E-04 -4.5800928447E-04 -3.1345578176E-04 + -2.6350591011E-04 -1.4034602592E-04 -4.4948278513E-04 + 3.5229363214E-04 4.0659350288E-04 -3.1084924045E-05 + -9.6446021178E-05 3.7778875781E-04 -5.8579782280E-05 + -7.2820608397E-04 -5.9902437485E-04 2.6578808119E-04 + 1.1409804697E-04 1.3337153595E-04 3.9191185627E-04 + 5.2794269358E-04 -4.7588306447E-04 1.4461984899E-04 + -4.4039546787E-04 -2.1185891472E-05 -6.2280506013E-04 + 4.3763646558E-05 1.4085482156E-05 -3.1082675770E-04 + 3.3545757092E-05 -4.8161876922E-04 4.4265912590E-04 + 4.8293708394E-04 -4.4193621831E-05 3.8467570378E-04 + 7.1797445168E-04 3.4479176610E-04 -5.1426167844E-05 + -7.7014681221E-04 5.7819321508E-04 -3.0402329331E-04 + -4.0453693280E-06 -8.4297011849E-04 -5.6195677350E-05 + -3.9122193330E-04 6.0153713909E-04 -2.6334363274E-05 + -2.1669016824E-04 8.9930203621E-06 -4.3262710326E-04 + 2.1969316657E-04 1.8037515152E-04 4.4060738578E-04 + -3.7978106616E-04 -3.9324111202E-05 -2.9199654214E-04 +:F: + -3.5400784632E-03 4.5819062231E-03 1.3664111300E-03 + -1.4078996645E-03 -2.0364416055E-03 1.5351999035E-03 + 1.1693107562E-02 -2.1346666003E-03 -2.5546231136E-03 + 1.1037218108E-02 -1.4719907685E-03 -8.3110726979E-04 + 1.1877135046E-02 1.2801944843E-03 1.2145389194E-03 + 1.4536563559E-02 3.6686659116E-03 4.5265661671E-04 + 1.0679739452E-02 -3.4050718644E-03 1.2427554643E-04 + 1.3763164058E-02 8.2039618064E-04 1.2914939329E-04 + 1.4112046741E-02 -1.2202681403E-03 -7.1726083519E-04 + -1.2960786203E-03 2.3607087135E-03 -2.8849124878E-03 + 5.8926886635E-03 -2.0196428315E-03 -1.1769190537E-03 + -1.1652797607E-02 -3.1360917982E-03 3.5584156486E-03 + -1.1172590465E-02 1.2530122961E-03 1.9758397479E-03 + -1.1525574797E-02 -9.8833180812E-04 -1.2736141917E-04 + -1.4494736380E-02 3.4853090809E-03 -2.5492112877E-03 + -1.1165596841E-02 -3.2592717471E-03 1.0225603455E-03 + -1.3572565310E-02 2.3870766463E-03 7.7490404693E-04 + -1.4358658714E-02 -2.6613752072E-04 -1.5145920647E-03 + 3.7831690601E-03 -3.2311359837E-04 1.4321117636E-02 + -3.1882553881E-03 4.2375874653E-04 -1.4119081402E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7482621898E+03 +:LATVEC_SCALE: + 1.8897160689E+01 1.8897160689E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.1844862739E-01 -9.3327487242E-02 1.4524447841E-01 + -9.3327487242E-02 7.3512557957E-01 -2.7098375957E-02 + 1.4524447841E-01 -2.7098375957E-02 4.8321371806E-01 +:STRESS: + 4.9037116758E+00 -1.0501711893E-02 6.1451986387E-04 + -1.0501711893E-02 5.5238599968E+00 1.0335093596E-02 + 6.1451986387E-04 1.0335093596E-02 5.8286794460E+00 +:CONSTRESS: + 6.0016726857E-01 -1.6435280181E-01 1.4342013510E-01 + -1.6435280181E-01 -6.0016726857E-01 -3.7515029075E-02 + 1.4342013510E-01 -3.7515029075E-02 -5.4487307349E+00 +:TOTSTRESS: + -4.7854303170E+00 8.1527026461E-02 1.2098234465E-03 + 8.1527026461E-02 -4.1885671487E+00 8.1559522158E-05 + 1.2098234465E-03 8.1559522158E-05 1.0326500696E-01 +:PRESIO: 6.4559597501E-01 +:PRES: -5.4187503729E+00 +:CONPRES: -1.8162435783E+00 +:TOTPRES: -2.9569108196E+00 +:PRESIG: 6.7957471053E-01 +:MIND: +Al - Al: 6.0392311833E+00 +C - C: 6.1563605018E+00 +Al - C: 6.1999520543E+00 + + +:MDSTEP: 8 +:MDTM: 3.91 +:TWIST: 0 +:TEL: 2400 +:TIO: 2475.28926998748 +:TEN: -2.6050340047E+00 +:KEN: 1.1170253923E-02 +:KENIG: 1.1758162025E-02 +:FEN: -2.6162042586E+00 +:UEN: -2.6091004721E+00 +:TSEN: -7.1037864725E-03 +:NPT_NP_HAMIL: 2.1971062411E-04 +:SNOSE[0]: 1.0054900312E+00 +:SNOSE[1]: 7.1705900318E-05 +:R: + 1.8892394898E+01 2.0023863873E-01 1.2761385009E-01 + 8.6963095157E-03 1.8850994902E+01 6.4489132889E+00 + 1.9783242732E-01 1.8765191735E+01 1.2508330874E+01 + 1.8813688048E+01 6.2590106130E+00 1.8767260095E+01 + 9.4788602036E-02 6.4164378237E+00 6.2895946288E+00 + 1.8860566295E+01 6.4070752898E+00 1.2580997378E+01 + 1.8679127670E+01 1.2425714443E+01 7.6982665218E-02 + 2.4952850262E-02 1.2636355894E+01 6.4126812875E+00 + 1.4462355369E-01 1.2460596831E+01 1.2640373565E+01 + 6.1712647823E+00 1.8890028025E+01 1.8717811540E+01 + 6.3087070802E+00 4.9145065582E-03 6.2095069186E+00 + 6.3158757388E+00 1.8758769805E+01 1.2725026132E+01 + 6.4461400155E+00 6.2857606491E+00 1.1070108831E-01 + 6.5144144097E+00 6.3994504229E+00 6.2842345572E+00 + 6.0843341414E+00 6.4652629891E+00 1.2511060254E+01 + 6.3049282031E+00 1.2354945769E+01 1.8880528105E+01 + 6.1936731114E+00 1.2771442473E+01 6.2911478613E+00 + 6.2447457910E+00 1.2600795318E+01 1.2473354382E+01 + 1.2658281728E+01 5.2606617108E-02 1.0944807376E-01 + 1.2490874273E+01 1.8885352694E+01 6.2325545336E+00 +:V: + -2.6392470980E-05 6.9954126614E-04 4.4242877551E-04 + 2.4710889736E-05 -1.6345146807E-04 5.1887960506E-04 + 7.1505216322E-04 -4.5884094110E-04 -3.1499803075E-04 + -2.5371679379E-04 -1.4130842404E-04 -4.4914305758E-04 + 3.6136701196E-04 4.0677169567E-04 -2.9901125008E-05 + -8.3920850163E-05 3.8019117877E-04 -5.8020618400E-05 + -7.1758484527E-04 -6.0068269298E-04 2.6524098519E-04 + 1.2545932806E-04 1.3377247761E-04 3.9108211316E-04 + 5.3854129299E-04 -4.7582271308E-04 1.4360714762E-04 + -4.4069617772E-04 -1.8987016871E-05 -6.2390781493E-04 + 4.8803830748E-05 1.2222187652E-05 -3.1111306545E-04 + 2.3684908727E-05 -4.8328742284E-04 4.4478267657E-04 + 4.7247955071E-04 -4.2935608514E-05 3.8552127328E-04 + 7.0661106802E-04 3.4306863187E-04 -5.1418585254E-05 + -7.8051169266E-04 5.7994685538E-04 -3.0558722444E-04 + -1.3321716701E-05 -8.4388597767E-04 -5.5136143037E-05 + -4.0172194579E-04 6.0220920406E-04 -2.5562974317E-05 + -2.2827990435E-04 8.7401005069E-06 -4.3293770063E-04 + 2.2684655692E-04 1.7928948873E-04 4.6706779929E-04 + -3.8536089809E-04 -3.8353199304E-05 -3.1839243831E-04 +:F: + -3.6255044035E-03 5.3054547585E-03 1.5404445633E-03 + -1.1201285071E-03 -2.3501031448E-03 1.8094815423E-03 + 1.1665107371E-02 -2.5101183225E-03 -2.9435418140E-03 + 1.0751408492E-02 -1.6368674997E-03 -9.7561167333E-04 + 1.1787859978E-02 1.5089472675E-03 1.4244781916E-03 + 1.4741341321E-02 4.2513548039E-03 5.3838702609E-04 + 1.0388408194E-02 -4.0289909148E-03 1.1939945373E-04 + 1.3966576260E-02 9.1041119838E-04 1.7521399098E-04 + 1.4207945906E-02 -1.4036526780E-03 -8.5339807503E-04 + -1.9809874183E-03 2.7540357166E-03 -3.3667018790E-03 + 6.3686710563E-03 -2.3370297740E-03 -1.3141789597E-03 + -1.1643918304E-02 -3.6398634795E-03 4.0764819831E-03 + -1.0932074621E-02 1.4866608504E-03 2.2772481697E-03 + -1.1369954262E-02 -1.1111531262E-03 -1.5387085632E-04 + -1.4677108160E-02 4.0547472469E-03 -2.9456961730E-03 + -1.0957531458E-02 -3.8249619217E-03 1.1743291729E-03 + -1.3717279415E-02 2.7123833103E-03 9.0935747514E-04 + -1.4512114408E-02 -2.8407284488E-04 -1.7432061350E-03 + 4.3711857861E-03 -3.6116850924E-04 1.4881398894E-02 + -3.7119034067E-03 5.0398706289E-04 -1.4630014898E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7482385573E+03 +:LATVEC_SCALE: + 1.8897127600E+01 1.8897127600E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.2197364062E-01 -9.6298217439E-02 1.4715566448E-01 + -9.6298217439E-02 7.3797585522E-01 -2.6834962547E-02 + 1.4715566448E-01 -2.6834962547E-02 4.8805642139E-01 +:STRESS: + 4.8866826002E+00 -1.2425415950E-02 -1.5283386361E-03 + -1.2425415950E-02 5.5113471784E+00 1.3434824127E-02 + -1.5283386361E-03 1.3434824127E-02 5.8277415775E+00 +:CONSTRESS: + 6.0536473225E-01 -1.6643033352E-01 1.4727993299E-01 + -1.6643033352E-01 -6.0536473225E-01 -4.0322255098E-02 + 1.4727993299E-01 -4.0322255098E-02 -5.4433665057E+00 +:TOTSTRESS: + -4.7700736919E+00 8.2557532030E-02 1.4040701234E-03 + 8.2557532030E-02 -4.1680065909E+00 5.2468424714E-05 + 1.4040701234E-03 5.2468424714E-05 1.0368134967E-01 +:PRESIO: 6.4933530574E-01 +:PRES: -5.4085904520E+00 +:CONPRES: -1.8144555019E+00 +:TOTPRES: -2.9447996444E+00 +:PRESIG: 6.8351084815E-01 +:MIND: +Al - Al: 5.9959668105E+00 +C - C: 6.1257328504E+00 +Al - C: 6.1822326817E+00 + + +:MDSTEP: 9 +:MDTM: 3.92 +:TWIST: 0 +:TEL: 2400 +:TIO: 2487.72498040723 +:TEN: -2.6051295536E+00 +:KEN: 1.1226372634E-02 +:KENIG: 1.1817234352E-02 +:FEN: -2.6163559263E+00 +:UEN: -2.6092792606E+00 +:TSEN: -7.0766656449E-03 +:NPT_NP_HAMIL: -8.1625209849E-05 +:SNOSE[0]: 1.0091060931E+00 +:SNOSE[1]: 1.0182978300E-04 +:R: + 1.8891204991E+01 2.2919837398E-01 1.4589840824E-01 + 9.6966149716E-03 1.8844171154E+01 6.4703574325E+00 + 2.2754255672E-01 1.8746175482E+01 1.2495280704E+01 + 1.8803366600E+01 6.2531382675E+00 1.8748708253E+01 + 1.0990546456E-01 6.4332374636E+00 6.2883853953E+00 + 1.8857320959E+01 6.4228256071E+00 1.2578612361E+01 + 1.8649657652E+01 1.2400831146E+01 8.7930515679E-02 + 3.0372385131E-02 1.2641866762E+01 6.4288232297E+00 + 1.6709377849E-01 1.2440911620E+01 1.2646285043E+01 + 6.1530317447E+00 1.8889254368E+01 1.8692006158E+01 + 6.3108188820E+00 5.3783404394E-03 6.1966453297E+00 + 6.3166385393E+00 1.8738725133E+01 1.2743451813E+01 + 6.4654354072E+00 6.2840019949E+00 1.2665000609E-01 + 6.5433640266E+00 6.4135758073E+00 6.2821099823E+00 + 6.0518578436E+00 6.4892531410E+00 1.2498398405E+01 + 6.3041757693E+00 1.2320029829E+01 1.8878273153E+01 + 6.1768448402E+00 1.2796315403E+01 6.2901087177E+00 + 6.2350611029E+00 1.2601125802E+01 1.2455457979E+01 + 1.2667787973E+01 5.9991218956E-02 1.2930248437E-01 + 1.2474801837E+01 1.8883751729E+01 6.2188453479E+00 +:V: + -2.9378608030E-05 7.0178005603E-04 4.4220806283E-04 + 2.3806618454E-05 -1.6496540456E-04 5.1864598860E-04 + 7.2226394653E-04 -4.5946298945E-04 -3.1649504767E-04 + -2.4391046069E-04 -1.4223792529E-04 -4.4841136375E-04 + 3.6992758296E-04 4.0667347177E-04 -2.8512909324E-05 + -7.1168746686E-05 3.8263334399E-04 -5.7323036258E-05 + -7.0641769826E-04 -6.0217164602E-04 2.6438791517E-04 + 1.3681297909E-04 1.3409345632E-04 3.8984726147E-04 + 5.4856858174E-04 -4.7536823610E-04 1.4231798208E-04 + -4.4105857668E-04 -1.6443682345E-05 -6.2468678520E-04 + 5.4171217969E-05 1.0087425982E-05 -3.1115697935E-04 + 1.3832531092E-05 -4.8481781774E-04 4.4681220973E-04 + 4.6171584891E-04 -4.1440902456E-05 3.8617420599E-04 + 6.9460352361E-04 3.4085693917E-04 -5.1377334945E-05 + -7.9010108533E-04 5.8150551742E-04 -3.0712448470E-04 + -2.2382451697E-05 -8.4430445718E-04 -5.3889987649E-05 + -4.1184901540E-04 6.0246001741E-04 -2.4653445835E-05 + -2.3969992380E-04 8.4678843426E-06 -4.3294139054E-04 + 2.3481029962E-04 1.7793629045E-04 4.9401596904E-04 + -3.9146600575E-04 -3.7188067104E-05 -3.4535099557E-04 +:F: + -3.7176773989E-03 6.0018923257E-03 1.7122765478E-03 + -8.2494830962E-04 -2.6535032844E-03 2.0653582906E-03 + 1.1630058122E-02 -2.8891155747E-03 -3.3148763049E-03 + 1.0458414359E-02 -1.7848676111E-03 -1.1164937488E-03 + 1.1703067577E-02 1.7291466451E-03 1.6288285496E-03 + 1.4938967360E-02 4.8147121849E-03 6.2867324206E-04 + 1.0105101527E-02 -4.6471566272E-03 1.1279078896E-04 + 1.4167731005E-02 9.9656935602E-04 2.2174039217E-04 + 1.4291427647E-02 -1.5748222773E-03 -9.9266520017E-04 + -2.6439102400E-03 3.1456972764E-03 -3.8186150088E-03 + 6.8413238997E-03 -2.6466897014E-03 -1.4477265045E-03 + -1.1638934336E-02 -4.1330852193E-03 4.5596871908E-03 + -1.0692140499E-02 1.7093171092E-03 2.5716644087E-03 + -1.1220248649E-02 -1.2318373628E-03 -1.8694924809E-04 + -1.4844015938E-02 4.6106542144E-03 -3.3282443757E-03 + -1.0754570290E-02 -4.3758612859E-03 1.3248929908E-03 + -1.3851817811E-02 3.0259976550E-03 1.0400926202E-03 + -1.4658276382E-02 -2.9018138379E-04 -1.9632648805E-03 + 4.9403342988E-03 -3.9331734118E-04 1.5488663722E-02 + -4.2298859455E-03 5.8645090217E-04 -1.5185833473E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7482114931E+03 +:LATVEC_SCALE: + 1.8897089706E+01 1.8897089706E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.2502268994E-01 -9.9163793402E-02 1.4911500597E-01 + -9.9163793402E-02 7.4011500595E-01 -2.6570944718E-02 + 1.4911500597E-01 -2.6570944718E-02 4.9266274251E-01 +:STRESS: + 4.8682880276E+00 -1.4362038343E-02 -4.3721683634E-03 + -1.4362038343E-02 5.4969400727E+00 1.6863383565E-02 + -4.3721683634E-03 1.6863383565E-02 5.8267321100E+00 +:CONSTRESS: + 6.1005476487E-01 -1.6830776217E-01 1.5188414841E-01 + -1.6830776217E-01 -6.1005476487E-01 -4.3457346567E-02 + 1.5188414841E-01 -4.3457346567E-02 -5.4381713268E+00 +:TOTSTRESS: + -4.7533201025E+00 8.3506007109E-02 1.6030259211E-03 + 8.3506007109E-02 -4.1467703019E+00 2.3018283923E-05 + 1.6030259211E-03 2.3018283923E-05 1.0410195927E-01 +:PRESIO: 6.5260014613E-01 +:PRES: -5.3973200701E+00 +:CONPRES: -1.8127237756E+00 +:TOTPRES: -2.9319961484E+00 +:PRESIG: 6.8694752224E-01 +:MIND: +Al - Al: 5.9527073698E+00 +C - C: 6.0930413675E+00 +Al - C: 6.1640513468E+00 + + +:MDSTEP: 10 +:MDTM: 4.48 +:TWIST: 0 +:TEL: 2400 +:TIO: 2497.1883153794 +:TEN: -2.6052555031E+00 +:KEN: 1.1269077887E-02 +:KENIG: 1.1862187250E-02 +:FEN: -2.6165245809E+00 +:UEN: -2.6094779553E+00 +:TSEN: -7.0466256444E-03 +:NPT_NP_HAMIL: -3.7261666034E-04 +:SNOSE[0]: 1.0141144015E+00 +:SNOSE[1]: 1.3664804090E-04 +:R: + 1.8889886242E+01 2.5824272247E-01 1.6416443089E-01 + 1.0664061156E-02 1.8837279465E+01 6.4917818203E+00 + 2.5752919317E-01 1.8727135088E+01 1.2482171221E+01 + 1.8793446623E+01 6.2472273996E+00 1.8730196737E+01 + 1.2536356445E-01 6.4500237560E+00 6.2872377735E+00 + 1.8854602244E+01 6.4386740052E+00 1.2576259296E+01 + 1.8620658473E+01 1.2375889456E+01 9.8835640174E-02 + 3.6259922822E-02 1.2647385322E+01 6.4449040967E+00 + 1.8996362040E-01 1.2421252359E+01 1.2652136931E+01 + 6.1347830915E+00 1.8888588003E+01 1.8666178337E+01 + 6.3131571442E+00 5.7484542706E-03 6.1837883456E+00 + 6.3169929611E+00 1.8718617583E+01 1.2761957058E+01 + 6.4842762494E+00 6.2823084050E+00 1.4262012691E-01 + 6.5717996399E+00 6.4275966047E+00 6.2799879774E+00 + 6.0190037400E+00 6.5132991806E+00 1.2485675126E+01 + 6.3030520701E+00 1.2285107662E+01 1.8876073730E+01 + 6.1596064612E+00 1.2821183847E+01 6.2891100536E+00 + 6.2249079049E+00 1.2601441456E+01 1.2437569757E+01 + 1.2677635030E+01 6.7313719343E-02 1.5027838425E-01 + 1.2458465168E+01 1.8882198207E+01 6.2040120762E+00 +:V: + -3.2393102559E-05 7.0362777243E-04 4.4152997498E-04 + 2.3125915003E-05 -1.6649916313E-04 5.1791617829E-04 + 7.2842996896E-04 -4.5977771601E-04 -3.1785910701E-04 + -2.3406319813E-04 -1.4308711225E-04 -4.4719085472E-04 + 3.7787996807E-04 4.0620470809E-04 -2.6923101707E-05 + -5.8212932012E-05 3.8500917723E-04 -5.6472562440E-05 + -6.9457395488E-04 -6.0335108393E-04 2.6317319501E-04 + 1.4810014552E-04 1.3430141201E-04 3.8812776072E-04 + 5.5787294839E-04 -4.7440861780E-04 1.4072294237E-04 + -4.4136721559E-04 -1.3559611624E-05 -6.2497794790E-04 + 5.9836775769E-05 7.6930325608E-06 -3.1088884230E-04 + 4.0078407436E-06 -4.8609305292E-04 4.4861471031E-04 + 4.5057199180E-04 -3.9719305595E-05 3.8654287010E-04 + 6.8182707386E-04 3.3809189533E-04 -5.1295879648E-05 + -7.9870877260E-04 5.8272806661E-04 -3.0855291372E-04 + -3.1205153666E-05 -8.4402715554E-04 -5.2450500735E-05 + -4.2148252856E-04 6.0214876890E-04 -2.3605341612E-05 + -2.5086507157E-04 8.1859953971E-06 -4.3253863691E-04 + 2.4347519679E-04 1.7629133468E-04 5.2136776493E-04 + -3.9798431893E-04 -3.5819325507E-05 -3.7281754314E-04 +:F: + -3.8185076469E-03 6.6671152421E-03 1.8791222076E-03 + -5.1918156845E-04 -2.9466874830E-03 2.3029390343E-03 + 1.1582411774E-02 -3.2707159495E-03 -3.6663141594E-03 + 1.0159136278E-02 -1.9151993590E-03 -1.2542076572E-03 + 1.1621850110E-02 1.9406546859E-03 1.8269864739E-03 + 1.5126233151E-02 5.3564563885E-03 7.2446480953E-04 + 9.8287216667E-03 -5.2550776069E-03 1.0426243231E-04 + 1.4366125332E-02 1.0781827147E-03 2.6904045439E-04 + 1.4361463601E-02 -1.7331320053E-03 -1.1351303561E-03 + -3.2840535677E-03 3.5391170743E-03 -4.2337578738E-03 + 7.3094910224E-03 -2.9451697696E-03 -1.5778271410E-03 + -1.1633154902E-02 -4.6161541154E-03 5.0022498637E-03 + -1.0453441829E-02 1.9087789565E-03 2.8561899718E-03 + -1.1077148998E-02 -1.3498621761E-03 -2.2389402577E-04 + -1.4990868861E-02 5.1512422849E-03 -3.6960611050E-03 + -1.0554367162E-02 -4.9028448206E-03 1.4735374025E-03 + -1.3976219345E-02 3.3246454686E-03 1.1692252867E-03 + -1.4796143645E-02 -2.8252348703E-04 -2.1756173790E-03 + 5.4897901563E-03 -4.2061877503E-04 1.6143497201E-02 + -4.7421355664E-03 6.7179273209E-04 -1.5788705440E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7481809403E+03 +:LATVEC_SCALE: + 1.8897046927E+01 1.8897046927E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.2724773241E-01 -1.0186742340E-01 1.5105800312E-01 + -1.0186742340E-01 7.4119255312E-01 -2.6297519157E-02 + 1.5105800312E-01 -2.6297519157E-02 4.9681654645E-01 +:STRESS: + 4.8483231860E+00 -1.6297798192E-02 -8.0072904134E-03 + -1.6297798192E-02 5.4803137920E+00 2.0549244193E-02 + -8.0072904134E-03 2.0549244193E-02 5.8256511375E+00 +:CONSTRESS: + 6.1432042957E-01 -1.6988512035E-01 1.5725865488E-01 + -1.6988512035E-01 -6.1432042957E-01 -4.6839306402E-02 + 1.5725865488E-01 -4.6839306402E-02 -5.4333602254E+00 +:TOTSTRESS: + -4.7353958831E+00 8.4315495140E-02 1.8066386500E-03 + 8.4315495140E-02 -4.1248008093E+00 -7.4569483297E-06 + 1.8066386500E-03 -7.4569483297E-06 1.0452563437E-01 +:PRESIO: 6.5508561066E-01 +:PRES: -5.3847627051E+00 +:CONPRES: -1.8111200751E+00 +:TOTPRES: -2.9185570193E+00 +:PRESIG: 6.8956380070E-01 +:MIND: +Al - Al: 5.9094770741E+00 +C - C: 6.0582569859E+00 +Al - C: 6.1453758186E+00 diff --git a/tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.refout b/tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.refout new file mode 100644 index 00000000..02275acd --- /dev/null +++ b/tests/Al18C2_NPTNP_aeqb_ortho_c/standard/Al18C2_NPTNP_aeqb_ortho_c.refout @@ -0,0 +1,653 @@ +*************************************************************************** +* SPARC (version December 03, 2025) * +* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * +* Distributed under GNU General Public License 3 (GPL) * +* Start time: Sun Apr 5 12:39:47 2026 * +*************************************************************************** + Input parameters +*************************************************************************** +LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 +LATVEC: +1.000000000000000 0.000000000000000 0.000000000000000 +0.000000000000000 1.000000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 +FD_GRID: 63 63 63 +FD_ORDER: 12 +BC: P P P +KPOINT_GRID: 1 1 1 +KPOINT_SHIFT: 0 0 0 +SPIN_TYP: 0 +ELEC_TEMP_TYPE: Fermi-Dirac +ELEC_TEMP: 2400 +EXCHANGE_CORRELATION: GGA_PBE +HUBBARD_FLAG: 0 +NSTATES: 80 +CHEB_DEGREE: 25 +CHEFSI_BOUND_FLAG: 0 +CALC_STRESS: 1 +TWTIME: 1E+09 +MD_FLAG: 1 +MD_METHOD: NPT_NP +MD_TIMESTEP: 1 +MD_NSTEP: 10 +ION_VEL_DSTR: 2 +ION_VEL_DSTR_RAND: 0 +ION_TEMP: 2400 +NPT_SCALE_VECS: 1 2 +NPT_SCALE_CONSTRAINTS: 12 +NPT_NP_ANGLES: 0 +NPT_NP_QMASS: 20000 +NPT_NP_BMASS: 40 +TARGET_STRESS: 0.1 0.1 0.1 0 0 0 GPa +MAXIT_SCF: 100 +MINIT_SCF: 2 +MAXIT_POISSON: 3000 +TOL_SCF: 1.00E-06 +POISSON_SOLVER: AAR +TOL_POISSON: 1.00E-08 +TOL_LANCZOS: 1.00E-02 +TOL_PSEUDOCHARGE: 1.00E-09 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +TOL_PRECOND: 9.00E-05 +PRECOND_KERKER_KTF: 1 +PRECOND_KERKER_THRESH: 0 +MIXING_PARAMETER: 1 +MIXING_HISTORY: 7 +PULAY_FREQUENCY: 1 +PULAY_RESTART: 0 +REFERENCE_CUTOFF: 0.5 +RHO_TRIGGER: 4 +NUM_CHEFSI: 1 +FIX_RAND: 0 +VERBOSITY: 1 +PRINT_FORCES: 1 +PRINT_ATOMS: 1 +PRINT_EIGEN: 0 +PRINT_DENSITY: 0 +PRINT_MDOUT: 1 +PRINT_VELS: 1 +PRINT_RESTART: 1 +PRINT_RESTART_FQ: 1 +PRINT_ENERGY_DENSITY: 0 +OUTPUT_FILE: Al18C2_NPTNP_aeqb_ortho_c +*************************************************************************** + Cell +*************************************************************************** +Lattice vectors (Bohr): +18.897259886000001 0.000000000000000 0.000000000000000 +0.000000000000000 18.897259886000001 0.000000000000000 +0.000000000000000 0.000000000000000 18.897259886000001 +Volume: 6.7483330373E+03 (Bohr^3) +Density: 7.5528236408E-02 (amu/Bohr^3), 8.4635982984E-01 (g/cc) +*************************************************************************** + Parallelization +*************************************************************************** +NP_SPIN_PARAL: 1 +NP_KPOINT_PARAL: 1 +NP_BAND_PARAL: 20 +NP_DOMAIN_PARAL: 1 1 3 +NP_DOMAIN_PHI_PARAL: 3 4 5 +EIG_SERIAL_MAXNS: 1500 +*************************************************************************** + Initialization +*************************************************************************** +Number of processors : 60 +Mesh spacing : 0.299957 (Bohr) +Number of symmetry adapted k-points: 1 +Output printed to : Al18C2_NPTNP_aeqb_ortho_c.out +MD output printed to : Al18C2_NPTNP_aeqb_ortho_c.aimd +Total number of atom types : 2 +Total number of atoms : 20 +Total number of electrons : 62 +Atom type 1 (valence electrons) : Al 3 +Pseudopotential : ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +Atomic mass : 26.9815385 +Pseudocharge radii of atom type 1 : 7.80 7.80 7.80 (x, y, z dir) +Number of atoms of type 1 : 18 +Atom type 2 (valence electrons) : C 4 +Pseudopotential : ../../../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 +Atomic mass : 12.011 +Pseudocharge radii of atom type 2 : 7.80 7.80 7.80 (x, y, z dir) +Number of atoms of type 2 : 2 +Estimated total memory usage : 1.12 GB +Estimated memory per processor : 19.17 MB +=================================================================== + Self Consistent Field (SCF#1) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6108380094E+00 2.289E-01 1.195 +2 -2.6486421014E+00 6.253E-01 0.342 +3 -2.6205617913E+00 3.918E-01 0.343 +4 -2.6239841224E+00 3.955E-01 0.336 +5 -2.6160787948E+00 9.259E-02 0.329 +6 -2.6158490133E+00 6.791E-02 0.329 +7 -2.6158207031E+00 5.819E-02 0.329 +8 -2.6157632975E+00 2.278E-02 0.325 +9 -2.6157886471E+00 3.691E-02 0.325 +10 -2.6157532966E+00 8.376E-03 0.327 +11 -2.6157543512E+00 1.017E-02 0.328 +12 -2.6157530173E+00 8.500E-04 0.327 +13 -2.6157533673E+00 5.077E-04 0.319 +14 -2.6157534797E+00 1.668E-04 0.324 +15 -2.6157535271E+00 8.735E-05 0.317 +16 -2.6157535305E+00 1.131E-04 0.317 +17 -2.6157535312E+00 1.333E-04 0.318 +18 -2.6157535317E+00 1.937E-05 0.315 +19 -2.6157535323E+00 1.598E-05 0.317 +20 -2.6157535348E+00 4.981E-06 0.313 +21 -2.6157535334E+00 2.958E-06 0.311 +22 -2.6157535333E+00 2.093E-06 0.306 +23 -2.6157535351E+00 1.339E-06 0.301 +24 -2.6157535335E+00 5.238E-07 0.305 +Total number of SCF: 24 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157535335E+00 (Ha/atom) +Total free energy : -5.2315070669E+01 (Ha) +Band structure energy : -9.0973556196E+00 (Ha) +Exchange correlation energy : -2.0462168950E+01 (Ha) +Self and correction energy : -7.6944567485E+01 (Ha) +-Entropy*kb*T : -1.4407939114E-01 (Ha) +Fermi level : -2.8356660939E-02 (Ha) +RMS force : 1.0668207057E-02 (Ha/Bohr) +Maximum force : 1.3289484404E-02 (Ha/Bohr) +Time for force calculation : 0.037 (sec) +Pressure : -5.4524793512E+00 (GPa) +Maximum stress : 5.8252493517E+00 (GPa) +Time for stress calculation : 0.069 (sec) +MD step time : 8.861 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8972551563982 18.8972551563982 18.897259886 +CHEB_DEGREE: 25 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.299956 (Bohr) +Mesh spacing in y-direction : 0.299956 (Bohr) +Mesh spacing in z direction : 0.299957 (Bohr) +=================================================================== + Self Consistent Field (SCF#2) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159715696E+00 3.769E-02 0.342 +2 -2.6165182061E+00 1.861E-01 0.326 +3 -2.6158153389E+00 5.359E-02 0.328 +4 -2.6159523462E+00 9.287E-02 0.325 +5 -2.6157574579E+00 3.523E-03 0.319 +6 -2.6157563689E+00 2.168E-03 0.320 +7 -2.6157564232E+00 9.735E-04 0.325 +8 -2.6157567022E+00 5.257E-04 0.324 +9 -2.6157569101E+00 3.437E-04 0.319 +10 -2.6157570506E+00 1.548E-04 0.315 +11 -2.6157571019E+00 7.275E-05 0.306 +12 -2.6157571083E+00 5.207E-05 0.307 +13 -2.6157571094E+00 9.009E-05 0.306 +14 -2.6157571097E+00 1.977E-05 0.306 +15 -2.6157571104E+00 5.950E-06 0.309 +16 -2.6157571110E+00 3.453E-06 0.304 +17 -2.6157571107E+00 2.281E-06 0.300 +18 -2.6157571130E+00 1.795E-06 0.300 +19 -2.6157571127E+00 7.283E-07 0.296 +Total number of SCF: 19 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157571127E+00 (Ha/atom) +Total free energy : -5.2315142254E+01 (Ha) +Band structure energy : -9.0981172284E+00 (Ha) +Exchange correlation energy : -2.0462505130E+01 (Ha) +Self and correction energy : -7.6944575396E+01 (Ha) +-Entropy*kb*T : -1.4398160911E-01 (Ha) +Fermi level : -2.8380045108E-02 (Ha) +RMS force : 1.0679385094E-02 (Ha/Bohr) +Maximum force : 1.3518525657E-02 (Ha/Bohr) +Time for force calculation : 0.034 (sec) +Pressure : -5.4509703268E+00 (GPa) +Maximum stress : 5.8275462109E+00 (GPa) +Time for stress calculation : 0.062 (sec) +MD step time : 6.159 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8972457004746 18.8972457004746 18.897259886 +CHEB_DEGREE: 25 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.299956 (Bohr) +Mesh spacing in y-direction : 0.299956 (Bohr) +Mesh spacing in z direction : 0.299957 (Bohr) +=================================================================== + Self Consistent Field (SCF#3) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159970116E+00 3.814E-02 0.340 +2 -2.6165598496E+00 1.879E-01 0.324 +3 -2.6158393799E+00 5.436E-02 0.326 +4 -2.6159781567E+00 9.358E-02 0.325 +5 -2.6157799792E+00 3.565E-03 0.327 +6 -2.6157788320E+00 2.241E-03 0.324 +7 -2.6157788733E+00 9.932E-04 0.326 +8 -2.6157791603E+00 5.353E-04 0.320 +9 -2.6157793768E+00 3.577E-04 0.321 +10 -2.6157795275E+00 1.586E-04 0.320 +11 -2.6157795819E+00 7.481E-05 0.312 +12 -2.6157795888E+00 5.306E-05 0.309 +13 -2.6157795899E+00 9.262E-05 0.306 +14 -2.6157795900E+00 1.958E-05 0.308 +15 -2.6157795909E+00 6.006E-06 0.308 +16 -2.6157795916E+00 3.498E-06 0.303 +17 -2.6157795912E+00 2.303E-06 0.300 +18 -2.6157795936E+00 1.875E-06 0.302 +19 -2.6157795931E+00 7.737E-07 0.297 +Total number of SCF: 19 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157795931E+00 (Ha/atom) +Total free energy : -5.2315591861E+01 (Ha) +Band structure energy : -9.0991074583E+00 (Ha) +Exchange correlation energy : -2.0463503283E+01 (Ha) +Self and correction energy : -7.6944599430E+01 (Ha) +-Entropy*kb*T : -1.4382186296E-01 (Ha) +Fermi level : -2.8414724580E-02 (Ha) +RMS force : 1.0736312717E-02 (Ha/Bohr) +Maximum force : 1.3783787401E-02 (Ha/Bohr) +Time for force calculation : 0.034 (sec) +Pressure : -5.4474043433E+00 (GPa) +Maximum stress : 5.8287845906E+00 (GPa) +Time for stress calculation : 0.062 (sec) +MD step time : 6.211 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8972315239821 18.8972315239821 18.897259886 +CHEB_DEGREE: 25 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.299956 (Bohr) +Mesh spacing in y-direction : 0.299956 (Bohr) +Mesh spacing in z direction : 0.299957 (Bohr) +=================================================================== + Self Consistent Field (SCF#4) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6157735032E+00 4.089E-03 0.329 +2 -2.6158299272E+00 1.597E-02 0.317 +3 -2.6158244227E+00 4.170E-03 0.313 +4 -2.6158252745E+00 7.939E-03 0.314 +5 -2.6158242057E+00 1.753E-04 0.309 +6 -2.6158242065E+00 5.464E-05 0.310 +7 -2.6158242081E+00 4.467E-05 0.312 +8 -2.6158242079E+00 1.310E-05 0.308 +9 -2.6158242086E+00 5.772E-06 0.303 +10 -2.6158242082E+00 4.213E-06 0.304 +11 -2.6158242080E+00 1.254E-06 0.298 +12 -2.6158242061E+00 1.003E-06 0.296 +13 -2.6158242079E+00 1.073E-06 0.301 +14 -2.6158242092E+00 5.091E-07 0.294 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6158242092E+00 (Ha/atom) +Total free energy : -5.2316484184E+01 (Ha) +Band structure energy : -9.1004010060E+00 (Ha) +Exchange correlation energy : -2.0465153487E+01 (Ha) +Self and correction energy : -7.6944637816E+01 (Ha) +-Entropy*kb*T : -1.4360346539E-01 (Ha) +Fermi level : -2.8465193139E-02 (Ha) +RMS force : 1.0847119916E-02 (Ha/Bohr) +Maximum force : 1.4080237550E-02 (Ha/Bohr) +Time for force calculation : 0.034 (sec) +Pressure : -5.4423579946E+00 (GPa) +Maximum stress : 5.8295223690E+00 (GPa) +Time for stress calculation : 0.062 (sec) +MD step time : 4.482 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8972126318074 18.8972126318074 18.897259886 +CHEB_DEGREE: 25 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.299956 (Bohr) +Mesh spacing in y-direction : 0.299956 (Bohr) +Mesh spacing in z direction : 0.299957 (Bohr) +=================================================================== + Self Consistent Field (SCF#5) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6158323845E+00 3.502E-03 0.326 +2 -2.6158869246E+00 5.410E-03 0.319 +3 -2.6158901224E+00 1.429E-02 0.319 +4 -2.6158867956E+00 7.959E-04 0.309 +5 -2.6158867929E+00 6.740E-04 0.308 +6 -2.6158867858E+00 8.011E-05 0.310 +7 -2.6158867838E+00 3.111E-05 0.310 +8 -2.6158867850E+00 2.103E-05 0.313 +9 -2.6158867849E+00 1.176E-05 0.305 +10 -2.6158867854E+00 5.708E-06 0.299 +11 -2.6158867862E+00 2.307E-06 0.301 +12 -2.6158867848E+00 1.666E-06 0.291 +13 -2.6158867858E+00 2.438E-06 0.300 +14 -2.6158867870E+00 1.029E-06 0.292 +15 -2.6158867864E+00 4.547E-07 0.294 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6158867864E+00 (Ha/atom) +Total free energy : -5.2317735728E+01 (Ha) +Band structure energy : -9.1019156356E+00 (Ha) +Exchange correlation energy : -2.0467466386E+01 (Ha) +Self and correction energy : -7.6944689706E+01 (Ha) +-Entropy*kb*T : -1.4332266406E-01 (Ha) +Fermi level : -2.8529139720E-02 (Ha) +RMS force : 1.1007686538E-02 (Ha/Bohr) +Maximum force : 1.4403632062E-02 (Ha/Bohr) +Time for force calculation : 0.034 (sec) +Pressure : -5.4357555418E+00 (GPa) +Maximum stress : 5.8296784218E+00 (GPa) +Time for stress calculation : 0.062 (sec) +MD step time : 4.772 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8971890237715 18.8971890237715 18.897259886 +CHEB_DEGREE: 25 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.299955 (Bohr) +Mesh spacing in y-direction : 0.299955 (Bohr) +Mesh spacing in z direction : 0.299957 (Bohr) +=================================================================== + Self Consistent Field (SCF#6) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159158879E+00 3.441E-03 0.320 +2 -2.6159683325E+00 3.083E-03 0.316 +3 -2.6159730576E+00 1.636E-02 0.321 +4 -2.6159685673E+00 1.304E-03 0.317 +5 -2.6159685347E+00 4.890E-04 0.313 +6 -2.6159685322E+00 6.989E-05 0.311 +7 -2.6159685314E+00 2.913E-05 0.308 +8 -2.6159685333E+00 1.915E-05 0.308 +9 -2.6159685329E+00 9.211E-06 0.307 +10 -2.6159685330E+00 4.761E-06 0.308 +11 -2.6159685337E+00 1.869E-06 0.303 +12 -2.6159685319E+00 3.135E-06 0.293 +13 -2.6159685325E+00 2.402E-06 0.301 +14 -2.6159685333E+00 1.077E-06 0.293 +15 -2.6159685329E+00 4.102E-07 0.294 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6159685329E+00 (Ha/atom) +Total free energy : -5.2319370658E+01 (Ha) +Band structure energy : -9.1037294616E+00 (Ha) +Exchange correlation energy : -2.0470436177E+01 (Ha) +Self and correction energy : -7.6944752301E+01 (Ha) +-Entropy*kb*T : -1.4297525249E-01 (Ha) +Fermi level : -2.8607484968E-02 (Ha) +RMS force : 1.1204686196E-02 (Ha/Bohr) +Maximum force : 1.4752884710E-02 (Ha/Bohr) +Time for force calculation : 0.034 (sec) +Pressure : -5.4278228442E+00 (GPa) +Maximum stress : 5.8293574064E+00 (GPa) +Time for stress calculation : 0.062 (sec) +MD step time : 4.793 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8971606890644 18.8971606890644 18.897259886 +CHEB_DEGREE: 25 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.299955 (Bohr) +Mesh spacing in y-direction : 0.299955 (Bohr) +Mesh spacing in z direction : 0.299957 (Bohr) +=================================================================== + Self Consistent Field (SCF#7) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6160224846E+00 3.430E-03 0.319 +2 -2.6160737012E+00 2.611E-03 0.321 +3 -2.6160765504E+00 1.074E-02 0.324 +4 -2.6160739428E+00 1.715E-03 0.310 +5 -2.6160739044E+00 6.347E-04 0.316 +6 -2.6160738996E+00 6.082E-05 0.309 +7 -2.6160738985E+00 2.897E-05 0.311 +8 -2.6160738992E+00 1.734E-05 0.309 +9 -2.6160738991E+00 1.025E-05 0.308 +10 -2.6160738994E+00 5.171E-06 0.305 +11 -2.6160739003E+00 2.230E-06 0.302 +12 -2.6160738985E+00 2.156E-06 0.297 +13 -2.6160739008E+00 2.073E-06 0.298 +14 -2.6160738995E+00 4.788E-07 0.292 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6160738995E+00 (Ha/atom) +Total free energy : -5.2321477991E+01 (Ha) +Band structure energy : -9.1059966773E+00 (Ha) +Exchange correlation energy : -2.0474049310E+01 (Ha) +Self and correction energy : -7.6944820605E+01 (Ha) +-Entropy*kb*T : -1.4255842606E-01 (Ha) +Fermi level : -2.8701055965E-02 (Ha) +RMS force : 1.1428264939E-02 (Ha/Bohr) +Maximum force : 1.5124259992E-02 (Ha/Bohr) +Time for force calculation : 0.034 (sec) +Pressure : -5.4187503729E+00 (GPa) +Maximum stress : 5.8286794460E+00 (GPa) +Time for stress calculation : 0.062 (sec) +MD step time : 4.495 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8971276000583 18.8971276000583 18.897259886 +CHEB_DEGREE: 25 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.299954 (Bohr) +Mesh spacing in y-direction : 0.299954 (Bohr) +Mesh spacing in z direction : 0.299957 (Bohr) +=================================================================== + Self Consistent Field (SCF#8) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6161538079E+00 3.415E-03 0.317 +2 -2.6162041898E+00 3.809E-03 0.319 +3 -2.6162074350E+00 1.297E-02 0.318 +4 -2.6162048520E+00 5.458E-03 0.314 +5 -2.6162042561E+00 2.102E-04 0.313 +6 -2.6162042576E+00 5.619E-05 0.314 +7 -2.6162042574E+00 3.671E-05 0.309 +8 -2.6162042593E+00 1.634E-05 0.307 +9 -2.6162042592E+00 8.982E-06 0.312 +10 -2.6162042596E+00 4.662E-06 0.311 +11 -2.6162042596E+00 2.539E-06 0.303 +12 -2.6162042586E+00 9.366E-07 0.304 +Total number of SCF: 12 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6162042586E+00 (Ha/atom) +Total free energy : -5.2324085172E+01 (Ha) +Band structure energy : -9.1088178388E+00 (Ha) +Exchange correlation energy : -2.0478284496E+01 (Ha) +Self and correction energy : -7.6944887514E+01 (Ha) +-Entropy*kb*T : -1.4207572945E-01 (Ha) +Fermi level : -2.8809225431E-02 (Ha) +RMS force : 1.1670786115E-02 (Ha/Bohr) +Maximum force : 1.5514307620E-02 (Ha/Bohr) +Time for force calculation : 0.034 (sec) +Pressure : -5.4085904520E+00 (GPa) +Maximum stress : 5.8277415775E+00 (GPa) +Time for stress calculation : 0.062 (sec) +MD step time : 3.913 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8970897060036 18.8970897060036 18.897259886 +CHEB_DEGREE: 25 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.299954 (Bohr) +Mesh spacing in y-direction : 0.299954 (Bohr) +Mesh spacing in z direction : 0.299957 (Bohr) +=================================================================== + Self Consistent Field (SCF#9) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6163062959E+00 3.404E-03 0.321 +2 -2.6163558484E+00 3.510E-03 0.318 +3 -2.6163584392E+00 1.061E-02 0.325 +4 -2.6163561357E+00 3.509E-03 0.314 +5 -2.6163559262E+00 2.797E-04 0.311 +6 -2.6163559261E+00 6.007E-05 0.313 +7 -2.6163559253E+00 3.373E-05 0.308 +8 -2.6163559267E+00 1.877E-05 0.309 +9 -2.6163559261E+00 1.111E-05 0.309 +10 -2.6163559266E+00 4.670E-06 0.303 +11 -2.6163559286E+00 1.904E-06 0.304 +12 -2.6163559263E+00 8.541E-07 0.300 +Total number of SCF: 12 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6163559263E+00 (Ha/atom) +Total free energy : -5.2327118525E+01 (Ha) +Band structure energy : -9.1121689037E+00 (Ha) +Exchange correlation energy : -2.0483121120E+01 (Ha) +Self and correction energy : -7.6944946060E+01 (Ha) +-Entropy*kb*T : -1.4153331290E-01 (Ha) +Fermi level : -2.8929939771E-02 (Ha) +RMS force : 1.1925834290E-02 (Ha/Bohr) +Maximum force : 1.6262235560E-02 (Ha/Bohr) +Time for force calculation : 0.034 (sec) +Pressure : -5.3973200701E+00 (GPa) +Maximum stress : 5.8267321100E+00 (GPa) +Time for stress calculation : 0.062 (sec) +MD step time : 3.924 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8970469272732 18.8970469272732 18.897259886 +CHEB_DEGREE: 25 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.299953 (Bohr) +Mesh spacing in y-direction : 0.299953 (Bohr) +Mesh spacing in z direction : 0.299957 (Bohr) +=================================================================== + Self Consistent Field (SCF#10) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6164753292E+00 3.376E-03 0.321 +2 -2.6165242480E+00 1.568E-03 0.319 +3 -2.6165274409E+00 1.290E-02 0.319 +4 -2.6165245799E+00 4.501E-04 0.312 +5 -2.6165246050E+00 1.060E-03 0.310 +6 -2.6165245818E+00 9.796E-05 0.311 +7 -2.6165245796E+00 2.331E-05 0.308 +8 -2.6165245808E+00 1.300E-05 0.310 +9 -2.6165245811E+00 8.301E-06 0.308 +10 -2.6165245812E+00 3.951E-06 0.305 +11 -2.6165245812E+00 2.181E-06 0.300 +12 -2.6165245794E+00 1.940E-06 0.295 +13 -2.6165245806E+00 1.765E-06 0.297 +14 -2.6165245809E+00 7.205E-07 0.295 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6165245809E+00 (Ha/atom) +Total free energy : -5.2330491619E+01 (Ha) +Band structure energy : -9.1159856413E+00 (Ha) +Exchange correlation energy : -2.0488556941E+01 (Ha) +Self and correction energy : -7.6944990667E+01 (Ha) +-Entropy*kb*T : -1.4093251289E-01 (Ha) +Fermi level : -2.9060856930E-02 (Ha) +RMS force : 1.2188393726E-02 (Ha/Bohr) +Maximum force : 1.7056588697E-02 (Ha/Bohr) +Time for force calculation : 0.034 (sec) +Pressure : -5.3847627051E+00 (GPa) +Maximum stress : 5.8256511375E+00 (GPa) +Time for stress calculation : 0.062 (sec) +MD step time : 4.483 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8969991509878 18.8969991509878 18.897259886 +CHEB_DEGREE: 25 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.299952 (Bohr) +Mesh spacing in y-direction : 0.299952 (Bohr) +Mesh spacing in z direction : 0.299957 (Bohr) +=================================================================== + Self Consistent Field (SCF#11) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6166564019E+00 3.393E-03 0.322 +2 -2.6167061096E+00 2.911E-03 0.315 +3 -2.6167106750E+00 1.589E-02 0.317 +4 -2.6167063600E+00 6.688E-04 0.311 +5 -2.6167063741E+00 9.499E-04 0.311 +6 -2.6167063563E+00 9.127E-05 0.313 +7 -2.6167063539E+00 3.623E-05 0.310 +8 -2.6167063545E+00 2.379E-05 0.307 +9 -2.6167063551E+00 1.367E-05 0.305 +10 -2.6167063550E+00 6.528E-06 0.306 +11 -2.6167063570E+00 3.049E-06 0.303 +12 -2.6167063550E+00 1.637E-06 0.307 +13 -2.6167063564E+00 1.397E-06 0.297 +14 -2.6167063570E+00 1.169E-06 0.295 +15 -2.6167063577E+00 2.849E-07 0.294 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6167063577E+00 (Ha/atom) +Total free energy : -5.2334127154E+01 (Ha) +Band structure energy : -9.1201981024E+00 (Ha) +Exchange correlation energy : -2.0494600268E+01 (Ha) +Self and correction energy : -7.6945017413E+01 (Ha) +-Entropy*kb*T : -1.4026981915E-01 (Ha) +Fermi level : -2.9199791906E-02 (Ha) +RMS force : 1.2455073954E-02 (Ha/Bohr) +Maximum force : 1.7894971237E-02 (Ha/Bohr) +Time for force calculation : 0.034 (sec) +Pressure : -5.3709126920E+00 (GPa) +Maximum stress : 5.8245214882E+00 (GPa) +Time for stress calculation : 0.062 (sec) +*************************************************************************** + Timing info +*************************************************************************** +Total walltime : 57.072 sec +___________________________________________________________________________ + +*************************************************************************** +* Material Physics & Mechanics Group, Georgia Tech * +* PI: Phanish Suryanarayana * +* List of contributors: See the documentation * +* Citation: See README.md or the documentation for details * +* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * +* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * +*************************************************************************** + diff --git a/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.inpt b/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.inpt new file mode 100644 index 00000000..7a614bed --- /dev/null +++ b/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.inpt @@ -0,0 +1,45 @@ +# nprocs: 48 +LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 +LATVEC: +1 0.0 0.0 +0.0 1.0 0.0 +0.0 0.0 1.0 +MESH_SPACING: 0.15 +BC: P P P +KPOINT_GRID: 1 1 1 +EXCHANGE_CORRELATION: GGA_PBE +TOL_SCF: 1e-6 +# TOL_POISSON: 1e-7 +# TOL_PSEUDOCHARGE: 1e-5 +MIXING_PARAMETER: 1.0 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +PRECOND_KERKER_THRESH: 0 + +# MD +MD_FLAG: 1 # 1 = MD, 0 = no MD (default) +ION_TEMP: 2400 # kelvin +# ION_TEMP_END: 1120 +MD_METHOD: NPT_NP # NVE, NVT_NH (Nose-Hoover), NVK_G (Gaussian) +#QMASS: 1600 # mass for NH thermostat +MD_TIMESTEP: 1 # fs +MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whichever comes first +#TWTIME: 1400 +RESTART_FLAG: 0 # 1 = restart MD from .restart file if present, 0 = start new +#ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) +EXTERNAL_PRESSURE: 0.1 GPa +#EXTERNAL_STRESS: 0 0 0 0 0 0 +NPT_NP_QMASS: 2000 +NPT_NP_BMASS: 0.5 +NPT_NP_ANGLES: 1 +#NPT_SCALE_CONSTRAINTS: 12 + +NSTATES: 80 + +# outputs +# CALC_PRES: 1 +CALC_STRESS: 1 # whether this selection changes the result of NPT? +PRINT_ATOMS: 1 +# PRINT_VELS: 1 +PRINT_FORCES: 1 +PRINT_MDOUT: 1 # print MD output to .aimd file diff --git a/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.ion b/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.ion new file mode 100644 index 00000000..b6420e8f --- /dev/null +++ b/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.ion @@ -0,0 +1,41 @@ +#CELL: 15 15 15 +#LATVEC +# 1.000000000000000 0.000000000000000 0.000000000000000 +# 0.000000000000000 1.000000000000000 0.000000000000000 +# 0.100000000000000 0.100000000000000 0.900000000000000 +#PBC: True True True +# + + +ATOM_TYPE: Al # atom type followed with valence charge +N_TYPE_ATOM: 18 # number of atoms of this type +PSEUDO_POT: ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +ATOMIC_MASS: 26.9815385 +COORD_FRAC: # coordinates follows +0.0 0.0 0.0 +0.0 0.0 0.333333 +0.0 0.0 0.666666 +0.0 0.333333 0.0 +0.0 0.333333 0.333333 +0.0 0.333333 0.666666 +0.0 0.666666 0.0 +0.0 0.666666 0.333333 +0.0 0.666666 0.666666 +0.333333 0.0 0.0 +0.333333 0.0 0.333333 +0.333333 0.0 0.666666 +0.333333 0.333333 0.0 +0.333333 0.333333 0.333333 +0.333333 0.333333 0.666666 +0.333333 0.666666 0.0 +0.333333 0.666666 0.333333 +0.333333 0.666666 0.666666 + + +ATOM_TYPE: C # atom type followed with valence charge +N_TYPE_ATOM: 2 # number of atoms of this type +PSEUDO_POT: ../../../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 +ATOMIC_MASS: 12.011 +COORD_FRAC: # coordinates follows +0.666666 0.0 0.0 +0.666666 0.0 0.333333 diff --git a/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.refaimd b/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.refaimd new file mode 100644 index 00000000..478c9ee0 --- /dev/null +++ b/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.refaimd @@ -0,0 +1,1168 @@ +:Description: + +:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr +:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu + where atu is the atomic unit of time, hbar/Ha +:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr +:Desc_MDTM: MD time. Unit=second +:Desc_TEL: Electronic temperature. Unit=Kelvin +:Desc_TIO: Ionic temperature. Unit=Kelvin +:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom +:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom +:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom + where N = number of particles, k = Boltzmann constant +:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom +:Desc_UEN: Internal energy. Unit=Ha/atom +:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom +:Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree +:Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 +:Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 +:Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during NPT_NP ensemble (has same magnitude as initial LatVec). Unit = Bohr +:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha +:Desc_SNOSE[0]: Position variable of the thermostat +:Desc_SNOSE[1]: Velocity variable of the thermostat +:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa +:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa +:Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa +:Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa +:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa + where N = number of particles, k = Boltzmann constant, V = volume +:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr + + + + +:MDSTEP: 1 +:MDTM: 108.22 +:TWIST: 0 +:TEL: 2400 +:TIO: 2400.34100675892 +:TEN: -2.6048830066E+00 +:KEN: 1.0832034410E-02 +:KENIG: 1.1402141485E-02 +:FEN: -2.6157150410E+00 +:UEN: -2.6085105470E+00 +:TSEN: -7.2044939720E-03 +:NPT_NP_HAMIL: 3.9730742692E-05 +:SNOSE[0]: 1.0000000000E+00 +:SNOSE[1]: 0.0000000000E+00 +:R: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 6.2990803296E+00 + 0.0000000000E+00 0.0000000000E+00 1.2598160659E+01 + 0.0000000000E+00 6.2990803296E+00 0.0000000000E+00 + 0.0000000000E+00 6.2990803296E+00 6.2990803296E+00 + 0.0000000000E+00 6.2990803296E+00 1.2598160659E+01 + 0.0000000000E+00 1.2598160659E+01 0.0000000000E+00 + 0.0000000000E+00 1.2598160659E+01 6.2990803296E+00 + 0.0000000000E+00 1.2598160659E+01 1.2598160659E+01 + 6.2990803296E+00 0.0000000000E+00 0.0000000000E+00 + 6.2990803296E+00 0.0000000000E+00 6.2990803296E+00 + 6.2990803296E+00 0.0000000000E+00 1.2598160659E+01 + 6.2990803296E+00 6.2990803296E+00 0.0000000000E+00 + 6.2990803296E+00 6.2990803296E+00 6.2990803296E+00 + 6.2990803296E+00 6.2990803296E+00 1.2598160659E+01 + 6.2990803296E+00 1.2598160659E+01 0.0000000000E+00 + 6.2990803296E+00 1.2598160659E+01 6.2990803296E+00 + 6.2990803296E+00 1.2598160659E+01 1.2598160659E+01 + 1.2598160659E+01 0.0000000000E+00 0.0000000000E+00 + 1.2598160659E+01 0.0000000000E+00 6.2990803296E+00 +:V: + -6.7508219471E-06 6.8757511333E-04 4.3936259751E-04 + 3.7355674748E-05 -1.5727035086E-04 5.1719530130E-04 + 6.4986381817E-04 -4.5410616975E-04 -3.0784982821E-04 + -3.2394420413E-04 -1.3629701048E-04 -4.4900402740E-04 + 2.9184532388E-04 4.0511689713E-04 -3.3972667286E-05 + -1.6699316312E-04 3.6969182646E-04 -5.9863047323E-05 + -7.8895517355E-04 -5.9299531459E-04 2.6594886271E-04 + 4.8087383076E-05 1.3106944640E-04 3.9308979242E-04 + 4.6023592582E-04 -4.7427996703E-04 1.4680549245E-04 + -4.4621372630E-04 -2.7196365394E-05 -6.1810882894E-04 + 2.1175060601E-05 1.9314811586E-05 -3.0796047527E-04 + 9.2718372712E-05 -4.7512761498E-04 4.3477901321E-04 + 5.4429990109E-04 -4.6900728960E-05 3.8053215229E-04 + 7.8083615873E-04 3.4893054559E-04 -5.1048600397E-05 + -7.0230039751E-04 5.7124856767E-04 -2.9842620845E-04 + 5.5677147840E-05 -8.3790479192E-04 -5.9249901635E-05 + -3.2642486895E-04 5.9659761738E-04 -2.8120762827E-05 + -1.4748613392E-04 9.7054915083E-06 -4.3002558872E-04 + 1.9870159961E-04 1.8287978851E-04 2.9481466056E-04 + -3.6274799964E-04 -4.1742829316E-05 -1.4673917629E-04 +:F: + -3.1865867304E-03 1.5691073569E-07 3.2887451767E-04 + -3.1867969948E-03 1.5679780661E-07 -3.2888315079E-04 + 1.1727462315E-02 1.5112074779E-07 -1.0295980294E-07 + 1.2514177913E-02 -2.4255236893E-04 1.2603028493E-04 + 1.2514238512E-02 -2.4257770441E-04 -1.2588447134E-04 + 1.3273721022E-02 -5.5110849704E-05 -1.6172278608E-07 + 1.2514167361E-02 2.4239090827E-04 1.2603021131E-04 + 1.2514197580E-02 2.4241658614E-04 -1.2587670702E-04 + 1.3273713776E-02 5.4947414716E-05 -1.7219206495E-07 + 3.1913326553E-03 1.5447602201E-07 3.2898229734E-04 + 3.1910235851E-03 1.5723003921E-07 -3.2899091181E-04 + -1.1727656192E-02 1.5297643617E-07 -1.0640492470E-07 + -1.2514221519E-02 -2.4260443963E-04 1.2599017968E-04 + -1.2514258466E-02 -2.4261933837E-04 -1.2583972076E-04 + -1.3273688023E-02 -5.5082056732E-05 -1.6619420131E-07 + -1.2514206525E-02 2.4244418796E-04 1.2599037490E-04 + -1.2514219649E-02 2.4246140903E-04 -1.2583614004E-04 + -1.3273689548E-02 5.4916067781E-05 -1.7119394114E-07 + -4.5959129433E-06 2.0008538926E-08 1.1883391101E-02 + -4.1151593946E-06 2.0663553556E-08 -1.1883097197E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483330373E+03 +:LATVEC_SCALE: + 1.8897259886E+01 1.8897259886E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0617480709E-01 -7.6076989132E-02 1.3809311820E-01 + -7.6076989132E-02 7.2214980551E-01 -2.9244328902E-02 + 1.3809311820E-01 -2.9244328902E-02 4.6067198938E-01 +:STRESS: + 4.9507361221E+00 2.6745351201E-08 5.6386739207E-07 + 2.6745351201E-08 5.5272713001E+00 -6.6719942595E-08 + 5.6386739207E-07 -6.6719942595E-08 5.7978276865E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2445613150E+00 -7.6077015877E-02 1.3809255434E-01 + -7.6077015877E-02 -4.8051214946E+00 -2.9244262182E-02 + 1.3809255434E-01 -2.9244262182E-02 -5.3371556971E+00 +:PRESIO: 6.2966553399E-01 +:PRES: -5.4252783696E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7956128356E+00 +:PRESIG: 6.6280582526E-01 +:MIND: +Al - Al: 6.2990803296E+00 +C - C: 6.2990803296E+00 +Al - C: 6.2990803296E+00 + + +:MDSTEP: 2 +:MDTM: 69.16 +:TWIST: 0 +:TEL: 2400 +:TIO: 2403.20689185341 +:TEN: -2.6048867745E+00 +:KEN: 1.0844967309E-02 +:KENIG: 1.1415755062E-02 +:FEN: -2.6157317418E+00 +:UEN: -2.6085326454E+00 +:TSEN: -7.1990963600E-03 +:NPT_NP_HAMIL: 4.4007444217E-05 +:SNOSE[0]: 1.0000217970E+00 +:SNOSE[1]: 4.3263635241E-06 +:R: + 1.8896572071E+01 2.8424387686E-02 1.8168943980E-02 + 1.4840634303E-03 1.8890357756E+01 6.3203080293E+00 + 2.7071818146E-02 1.8878084971E+01 1.2585139325E+01 + 1.8883750353E+01 6.2933038452E+00 1.8878258018E+01 + 1.2285702188E-02 6.3156890901E+00 6.2975262970E+00 + 1.8890244446E+01 6.3142262874E+00 1.2595391087E+01 + 1.8864500187E+01 1.2573384427E+01 1.0996503734E-02 + 2.2046146794E-03 1.2603315714E+01 6.3151810402E+00 + 1.9263585611E-02 1.2578285699E+01 1.2603934755E+01 + 6.2805815015E+00 1.8895731861E+01 1.8871270759E+01 + 6.2999008322E+00 7.9689539088E-04 6.2861961245E+00 + 6.3025944080E+00 1.8877215936E+01 1.2615839568E+01 + 6.3212424501E+00 6.2970042399E+00 1.5733371106E-02 + 6.3310283502E+00 6.3133663430E+00 6.2968203795E+00 + 6.2697095387E+00 6.3225586561E+00 1.2585528896E+01 + 6.3010610520E+00 1.2563255104E+01 1.8894370436E+01 + 6.2852498832E+00 1.2622560677E+01 6.2977682153E+00 + 6.2926415267E+00 1.2598293687E+01 1.2580088584E+01 + 1.2606139261E+01 7.5602571890E-03 1.2651419849E-02 + 1.2582923965E+01 1.8895133675E+01 6.2924029382E+00 +:V: + -9.4488510665E-06 6.8789524638E-04 4.3971152607E-04 + 3.4803637930E-05 -1.5741741465E-04 5.1705344528E-04 + 6.5972473524E-04 -4.5424738847E-04 -3.0803627006E-04 + -3.1351538991E-04 -1.3659694580E-04 -4.4896992954E-04 + 3.0231448365E-04 4.0502540934E-04 -3.3983342641E-05 + -1.5574378462E-04 3.6991217378E-04 -5.9833200599E-05 + -7.7856197925E-04 -5.9303316588E-04 2.6605742342E-04 + 5.8692138002E-05 1.3131428423E-04 3.9300287091E-04 + 4.7146020548E-04 -4.7432850441E-04 1.4675878507E-04 + -4.4385820366E-04 -2.7035230530E-05 -6.1806422789E-04 + 2.4039614663E-05 1.9166806737E-05 -3.0829695162E-04 + 8.2862611830E-05 -4.7534660503E-04 4.3504266715E-04 + 5.3386593764E-04 -4.6997000281E-05 3.8076699407E-04 + 7.7038320623E-04 3.4867785238E-04 -5.1148079853E-05 + -7.1354555934E-04 5.7144838586E-04 -2.9860852494E-04 + 4.5255474762E-05 -8.3794396554E-04 -5.9083573366E-05 + -3.3702327468E-04 5.9695817305E-04 -2.8157549229E-05 + -1.5872412852E-04 9.7190826724E-06 -4.3013859778E-04 + 1.9930960437E-04 1.8282242687E-04 3.1755416631E-04 + -3.6325401131E-04 -4.1683649678E-05 -1.6945664261E-04 +:F: + -3.2332291533E-03 7.6270649496E-04 4.9925993125E-04 + -2.8853162349E-03 -3.5039590977E-04 -1.0432766026E-05 + 1.1740669235E-02 -3.3792946762E-04 -4.4022036870E-04 + 1.2298048591E-02 -4.7084629234E-04 -4.4000753512E-05 + 1.2398524818E-02 2.5085220926E-05 1.0121112818E-04 + 1.3492135027E-02 5.8026348504E-04 7.0730517485E-05 + 1.2209877656E-02 -3.3219832350E-04 1.2940336140E-04 + 1.2719407956E-02 3.4028674041E-04 -8.2376437228E-05 + 1.3437043413E-02 -1.7193578598E-04 -1.0992386161E-04 + 2.4101771577E-03 3.8390278798E-04 -2.2173754626E-04 + 3.6251321116E-03 -3.5232724627E-04 -4.7039936315E-04 + -1.1722734647E-02 -5.2213291320E-04 6.2632213275E-04 + -1.2308633431E-02 1.2617628137E-05 4.3289631236E-04 + -1.2352036495E-02 -3.5928627083E-04 -1.0868387998E-04 + -1.3488540447E-02 5.3256663422E-04 -4.3484599967E-04 + -1.2283004976E-02 -3.3709623171E-04 2.7064592953E-04 + -1.2706329473E-02 6.1694102556E-04 3.7117675749E-05 + -1.3467396702E-02 -2.2322563676E-05 -2.6752045794E-04 + 6.4925581852E-04 -6.0783765793E-05 1.2202328646E-02 + -5.3305022469E-04 6.2884753478E-05 -1.2179774201E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7479064462E+03 +:LATVEC_SCALE: + 1.8896906512E+01 1.8896860909E+01 1.8896817635E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -6.5493980259E-07 1.0000000000E+00 0.0000000000E+00 + 1.1888254881E-06 -2.5176062806E-07 1.0000000000E+00 +:STRIO: + 7.0589030971E-01 -7.8712702613E-02 1.3855751033E-01 + -7.8712702613E-02 7.2255578788E-01 -2.8779463464E-02 + 1.3855751033E-01 -2.8779463464E-02 4.6292543200E-01 +:STRESS: + 4.9432445453E+00 -1.6162053833E-03 1.5565104133E-03 + -1.6162053833E-03 5.5300159997E+00 6.0879517575E-04 + 1.5565104133E-03 6.0879517575E-04 5.8015346555E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2373542356E+00 -7.7096497229E-02 1.3700099992E-01 + -7.7096497229E-02 -4.8074602119E+00 -2.9388258640E-02 + 1.3700099992E-01 -2.9388258640E-02 -5.3386092235E+00 +:PRESIO: 6.3045717653E-01 +:PRES: -5.4249317335E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7944745570E+00 +:PRESIG: 6.6363913319E-01 +:MIND: +Al - Al: 6.2554973255E+00 +C - C: 6.2798060552E+00 +Al - C: 6.2830267104E+00 + + +:MDSTEP: 3 +:MDTM: 69.19 +:TWIST: 0 +:TEL: 2400 +:TIO: 2407.81364109559 +:TEN: -2.6049046921E+00 +:KEN: 1.0865756216E-02 +:KENIG: 1.1437638122E-02 +:FEN: -2.6157704483E+00 +:UEN: -2.6085800736E+00 +:TSEN: -7.1903747321E-03 +:NPT_NP_HAMIL: 3.3698060620E-05 +:SNOSE[0]: 1.0005002142E+00 +:SNOSE[1]: 2.2555639158E-05 +:R: + 1.8895419025E+01 5.6866949914E-02 3.6349846153E-02 + 2.8624369599E-03 1.8883044316E+01 6.3413814652E+00 + 5.4546032016E-02 1.8858501213E+01 1.2571811333E+01 + 1.8870336882E+01 6.2873747307E+00 1.8858817485E+01 + 2.5001805368E-02 6.3321591004E+00 6.2958286345E+00 + 1.8883357263E+01 6.3292516023E+00 1.2592329612E+01 + 1.8831812667E+01 1.2548337504E+01 2.1994270997E-02 + 4.8495747750E-03 1.2608213114E+01 6.3311265116E+00 + 3.8994994861E-02 1.2558141029E+01 1.2609408096E+01 + 6.2620636781E+00 1.8893813297E+01 1.8844838874E+01 + 6.3007367182E+00 1.5797334115E-03 6.2731518049E+00 + 6.3055849511E+00 1.8856756959E+01 1.2633239785E+01 + 6.3428487769E+00 6.2947960165E+00 3.1477083434E-02 + 6.3624235978E+00 6.3275009457E+00 6.2944096933E+00 + 6.2397714949E+00 6.3459122403E+00 1.2572590624E+01 + 6.3025107946E+00 1.2528076895E+01 1.8891048442E+01 + 6.2708633085E+00 1.2646707029E+01 6.2963102056E+00 + 6.2856254580E+00 1.2598156357E+01 1.2561717393E+01 + 1.2613930860E+01 1.5113556651E-02 2.6251322228E-02 + 1.2567409500E+01 1.8892611848E+01 6.2846294637E+00 +:V: + -1.2183516959E-05 6.8855913434E-04 4.4001474904E-04 + 3.2489387132E-05 -1.5778870955E-04 5.1695467201E-04 + 6.6930281983E-04 -4.5447823954E-04 -3.0845888114E-04 + -3.0313838006E-04 -1.3702631046E-04 -4.4888234273E-04 + 3.1255358791E-04 4.0498102008E-04 -3.3789599103E-05 + -1.4424646943E-04 3.7050409206E-04 -5.9716380653E-05 + -7.6808744847E-04 -5.9330325678E-04 2.6605460574E-04 + 6.9441851054E-05 1.3158342939E-04 3.9278156517E-04 + 4.8260967184E-04 -4.7435885639E-04 1.4655372830E-04 + -4.4195859556E-04 -2.6538586945E-05 -6.1821434554E-04 + 2.7261292694E-05 1.8716233690E-05 -3.0861955799E-04 + 7.2978876990E-05 -4.7579800952E-04 4.3564142199E-04 + 5.2337700823E-04 -4.6857293916E-05 3.8109507290E-04 + 7.5973271797E-04 3.4817472010E-04 -5.1215023765E-05 + -7.2465567496E-04 5.7189403995E-04 -2.9902469350E-04 + 3.5009932485E-05 -8.3810791775E-04 -5.8770200859E-05 + -3.4763075336E-04 5.9737091182E-04 -2.8046093153E-05 + -1.7005136710E-04 9.6670154472E-06 -4.3028761249E-04 + 2.0105337775E-04 1.8257429143E-04 3.4078825542E-04 + -3.6460256583E-04 -4.1485434230E-05 -1.9268538481E-04 +:F: + -3.2850375256E-03 1.5308847366E-03 6.7288901281E-04 + -2.5860355229E-03 -6.9661943298E-04 3.0649277042E-04 + 1.1746807512E-02 -6.8478664531E-04 -8.7742157847E-04 + 1.2069842184E-02 -6.9172424221E-04 -2.1001305697E-04 + 1.2287207104E-02 2.8847274509E-04 3.2619615441E-04 + 1.3707447756E-02 1.2125949630E-03 1.4456054666E-04 + 1.1902239020E-02 -9.2333392429E-04 1.3338659704E-04 + 1.2925889379E-02 4.3628354768E-04 -4.0653790161E-05 + 1.3592697960E-02 -3.9387723830E-04 -2.2414758192E-04 + 1.6453043200E-03 7.7133622540E-04 -7.7240291986E-04 + 4.0674198661E-03 -7.0012932182E-04 -6.1373930205E-04 + -1.1713119462E-02 -1.0454990432E-03 1.2461829471E-03 + -1.2094444466E-02 2.6939983537E-04 7.4178829770E-04 + -1.2187398933E-02 -4.7875290876E-04 -9.9256782493E-05 + -1.3701510441E-02 1.1230856193E-03 -8.6681761982E-04 + -1.2053434987E-02 -9.2248752501E-04 4.1570541079E-04 + -1.2892462641E-02 9.8570741696E-04 1.9655198900E-04 + -1.3657330415E-02 -9.0979831166E-05 -5.2960123504E-04 + 1.2911232283E-03 -1.1793072344E-04 1.2558343022E-02 + -1.0652039367E-03 1.2835574717E-04 -1.2508042881E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7470531387E+03 +:LATVEC_SCALE: + 1.8896200123E+01 1.8896062503E+01 1.8895932724E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.9741303862E-06 1.0000000000E+00 0.0000000000E+00 + 3.5580402690E-06 -7.5672410367E-07 9.9999999999E-01 +:STRIO: + 7.0626737720E-01 -8.1413981417E-02 1.3924320232E-01 + -8.1413981417E-02 7.2338300392E-01 -2.8340557960E-02 + 1.3924320232E-01 -2.8340557960E-02 4.6558641401E-01 +:STRESS: + 4.9344650651E+00 -3.3056439185E-03 2.6013404392E-03 + -3.3056439185E-03 5.5308063903E+00 1.6879419734E-03 + 2.6013404392E-03 1.6879419734E-03 5.8052513783E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2281976879E+00 -7.8108337499E-02 1.3664186189E-01 + -7.8108337499E-02 -4.8074233864E+00 -3.0028499933E-02 + 1.3664186189E-01 -3.0028499933E-02 -5.3396649643E+00 +:PRESIO: 6.3174559837E-01 +:PRES: -5.4235076112E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7917620129E+00 +:PRESIG: 6.6499536671E-01 +:MIND: +Al - Al: 6.2118620818E+00 +C - C: 6.2585928775E+00 +Al - C: 6.2666853378E+00 + + +:MDSTEP: 4 +:MDTM: 52.81 +:TWIST: 0 +:TEL: 2400 +:TIO: 2410.73129504618 +:TEN: -2.6049514574E+00 +:KEN: 1.0878922732E-02 +:KENIG: 1.1451497612E-02 +:FEN: -2.6158303802E+00 +:UEN: -2.6086521354E+00 +:TSEN: -7.1782447049E-03 +:NPT_NP_HAMIL: 2.6520947401E-05 +:SNOSE[0]: 1.0021527396E+00 +:SNOSE[1]: 5.4911639530E-05 +:R: + 1.8893798876E+01 8.5330578931E-02 5.4533506961E-02 + 4.1442989785E-03 1.8875311473E+01 6.3622931756E+00 + 8.2399438637E-02 1.8838510734E+01 1.2558170997E+01 + 1.8857021155E+01 6.2812894419E+00 1.8838946352E+01 + 3.8133403461E-02 6.3484850095E+00 6.2939957397E+00 + 1.8876609938E+01 6.3441648661E+00 1.2588979728E+01 + 1.8799212248E+01 1.2523018836E+01 3.2984260268E-02 + 7.9393586827E-03 1.2612850622E+01 6.3469040239E+00 + 5.9182731232E-02 1.2537734267E+01 1.2614570470E+01 + 6.2435150340E+00 1.8891516971E+01 1.8817964809E+01 + 6.3016021489E+00 2.3357603244E-03 6.2599525075E+00 + 6.3080496595E+00 1.8835879652E+01 1.2650366594E+01 + 6.3638887226E+00 6.2924657120E+00 4.7228642242E-02 + 6.3932455758E+00 6.3414674685E+00 6.2918497665E+00 + 6.2092836519E+00 6.3691412600E+00 1.2559340091E+01 + 6.3034362641E+00 1.2492633535E+01 1.8887299245E+01 + 6.2559259519E+00 1.2670590868E+01 6.2947122584E+00 + 6.2780312417E+00 1.2597744895E+01 1.2543051745E+01 + 1.2621578254E+01 2.2649137598E-02 4.0815239570E-02 + 1.2551587720E+01 1.8889699430E+01 6.2757408478E+00 +:V: + -1.4947958038E-05 6.8907600140E-04 4.3995940343E-04 + 3.0389908707E-05 -1.5826666287E-04 5.1652742976E-04 + 6.7810183743E-04 -4.5448049401E-04 -3.0889289054E-04 + -2.9261923417E-04 -1.3747969278E-04 -4.4841708370E-04 + 3.2233042717E-04 4.0469004510E-04 -3.3369587267E-05 + -1.3241517873E-04 3.7119809713E-04 -5.9467825454E-05 + -7.5699743511E-04 -5.9339329447E-04 2.6575038936E-04 + 8.0274436402E-05 1.3178106709E-04 3.9214415878E-04 + 4.9331877805E-04 -4.7402704466E-04 1.4608230615E-04 + -4.4018764906E-04 -2.5685693665E-05 -6.1811513344E-04 + 3.0822225521E-05 1.7954996754E-05 -3.0870825540E-04 + 6.3030642248E-05 -4.7614106862E-04 4.3625537261E-04 + 5.1247855056E-04 -4.6448270628E-05 3.8124471812E-04 + 7.4835632178E-04 3.4717108003E-04 -5.1219028057E-05 + -7.3509662362E-04 5.7217705079E-04 -2.9945733724E-04 + 2.4926375555E-05 -8.3780053309E-04 -5.8267697141E-05 + -3.5798037337E-04 5.9740259051E-04 -2.7770009471E-05 + -1.8132875301E-04 9.5499771191E-06 -4.3015989873E-04 + 2.0376648484E-04 1.8201236079E-04 3.6431473786E-04 + -3.6653248286E-04 -4.1113852712E-05 -2.1631957668E-04 +:F: + -3.3441538114E-03 2.2992723846E-03 8.4802681627E-04 + -2.2904877869E-03 -1.0371983610E-03 6.1988726344E-04 + 1.1745397403E-02 -1.0395296900E-03 -1.3088643470E-03 + 1.1829894733E-02 -9.0372653422E-04 -3.7175667302E-04 + 1.2180304957E-02 5.4605224837E-04 5.4871942139E-04 + 1.3919303989E-02 1.8391670726E-03 2.2091970568E-04 + 1.1593244662E-02 -1.5271865120E-03 1.3703621767E-04 + 1.3133228189E-02 5.3075980362E-04 -1.9867549077E-07 + 1.3739725439E-02 -6.0921779297E-04 -3.4241040514E-04 + 8.9596971437E-04 1.1612473457E-03 -1.3187394580E-03 + 4.5153597977E-03 -1.0418105829E-03 -7.5739352226E-04 + -1.1699995625E-02 -1.5678713571E-03 1.8545551513E-03 + -1.1873092648E-02 5.2502633287E-04 1.0514893001E-03 + -1.2021632692E-02 -6.0006247930E-04 -9.7082462982E-05 + -1.3910466059E-02 1.7132207889E-03 -1.2944788585E-03 + -1.1826126920E-02 -1.5097606571E-03 5.6162673526E-04 + -1.3071856994E-02 1.3466870072E-03 3.5125927274E-04 + -1.3842667457E-02 -1.5034316338E-04 -7.8522098728E-04 + 1.9239362540E-03 -1.7125503485E-04 1.2951586911E-02 + -1.5958851446E-03 1.9652918118E-04 -1.2868961405E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7457718895E+03 +:LATVEC_SCALE: + 1.8895140173E+01 1.8894863203E+01 1.8894603434E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -3.9689704512E-06 9.9999999999E-01 0.0000000000E+00 + 7.1093180528E-06 -1.5214306004E-06 9.9999999997E-01 +:STRIO: + 7.0629229511E-01 -8.4057184510E-02 1.3995775965E-01 + -8.4057184510E-02 7.2359986032E-01 -2.7889682800E-02 + 1.3995775965E-01 -2.7889682800E-02 4.6800158716E-01 +:STRESS: + 4.9244581211E+00 -5.0541954430E-03 3.0826354708E-03 + -5.0541954430E-03 5.5296677885E+00 3.2264108414E-03 + 3.0826354708E-03 3.2264108414E-03 5.8090136232E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2181658260E+00 -7.9002989067E-02 1.3687512418E-01 + -7.9002989067E-02 -4.8060679282E+00 -3.1116093642E-02 + 1.3687512418E-01 -3.1116093642E-02 -5.3410120361E+00 +:PRESIO: 6.3263124753E-01 +:PRES: -5.4210465110E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7884152634E+00 +:PRESIG: 6.6592762898E-01 +:MIND: +Al - Al: 6.1681867647E+00 +C - C: 6.2354092121E+00 +Al - C: 6.2500100851E+00 + + +:MDSTEP: 5 +:MDTM: 61.56 +:TWIST: 0 +:TEL: 2400 +:TIO: 2409.78290925197 +:TEN: -2.6050363072E+00 +:KEN: 1.0874642945E-02 +:KENIG: 1.1446992574E-02 +:FEN: -2.6159109502E+00 +:UEN: -2.6087483433E+00 +:TSEN: -7.1626068982E-03 +:NPT_NP_HAMIL: 3.4940879376E-05 +:SNOSE[0]: 1.0054397078E+00 +:SNOSE[1]: 9.0834686203E-05 +:R: + 1.8891707966E+01 1.1380150857E-01 7.2700169801E-02 + 5.3381155243E-03 1.8867152819E+01 6.3830222307E+00 + 1.1059174875E-01 1.8818123946E+01 1.2544218497E+01 + 1.8843808955E+01 6.2750472116E+00 1.8818660887E+01 + 5.1657395426E-02 6.3646507090E+00 6.2920357857E+00 + 1.8870014427E+01 6.3589646153E+00 1.2585344612E+01 + 1.8766729221E+01 1.2497439700E+01 4.3951028445E-02 + 1.1475866389E-02 1.2617221164E+01 6.3624904854E+00 + 7.9802521753E-02 1.2517083049E+01 1.2619406212E+01 + 6.2249342762E+00 1.8888853867E+01 1.8790661469E+01 + 6.3025098831E+00 3.0520254907E-03 6.2466099005E+00 + 6.3099848921E+00 1.8814589858E+01 1.2667212489E+01 + 6.3843395916E+00 6.2900236482E+00 6.2976371530E-02 + 6.4234558929E+00 6.3552400632E+00 6.2891421685E+00 + 6.1782814515E+00 6.3922312059E+00 1.2545777134E+01 + 6.3038436454E+00 1.2456950995E+01 1.8883126850E+01 + 6.2404520482E+00 1.2694187069E+01 6.2929799063E+00 + 6.2698626910E+00 1.2597054006E+01 1.2524105071E+01 + 1.2629117041E+01 3.0152187379E-02 5.6351265007E-02 + 1.2535436816E+01 1.8886400255E+01 6.2657213547E+00 +:V: + -1.7735039002E-05 6.8913160690E-04 4.3934875234E-04 + 2.8493642009E-05 -1.5877318969E-04 5.1553644793E-04 + 6.8578809482E-04 -4.5405542219E-04 -3.0919217418E-04 + -2.8186238341E-04 -1.3788573755E-04 -4.4736992449E-04 + 3.3147929114E-04 4.0396562486E-04 -3.2712078184E-05 + -1.2022378813E-04 3.7181882707E-04 -5.9059540308E-05 + -7.4497971188E-04 -5.9304467997E-04 2.6502559145E-04 + 9.1126573256E-05 1.3184611402E-04 3.9091530584E-04 + 5.0333085274E-04 -4.7311488735E-04 1.4527682510E-04 + -4.3833719051E-04 -2.4465753585E-05 -6.1748243565E-04 + 3.4703617807E-05 1.6883061711E-05 -3.0842356291E-04 + 5.3017424124E-05 -4.7615863042E-04 4.3667402537E-04 + 5.0097305674E-04 -4.5752872418E-05 3.8104366412E-04 + 7.3594666533E-04 3.4551217734E-04 -5.1142977178E-05 + -7.4450693844E-04 5.7203726838E-04 -2.9976558445E-04 + 1.5016591060E-05 -8.3664529738E-04 -5.7550818980E-05 + -3.6787899202E-04 5.9677737028E-04 -2.7321671739E-05 + -1.9244181232E-04 9.3723101696E-06 -4.2955651917E-04 + 2.0733081958E-04 1.8106377923E-04 3.8798092637E-04 + -3.6886950692E-04 -4.0546573400E-05 -2.4026497760E-04 +:F: + -3.4117970982E-03 3.0618886467E-03 1.0239304313E-03 + -1.9978581217E-03 -1.3707890034E-03 9.2749434798E-04 + 1.1735254948E-02 -1.4004989424E-03 -1.7324663543E-03 + 1.1578804752E-02 -1.1052151666E-03 -5.2873333017E-04 + 1.2077673872E-02 7.9640886169E-04 7.6808155691E-04 + 1.4127162903E-02 2.4572037223E-03 2.9961263542E-04 + 1.1285102861E-02 -2.1397815784E-03 1.3968363252E-04 + 1.3340732004E-02 6.2372017773E-04 3.9748699158E-05 + 1.3876864925E-02 -8.1739854935E-04 -4.6473753395E-04 + 1.6404476054E-04 1.5533753248E-03 -1.8550926550E-03 + 4.9688241221E-03 -1.3762511446E-03 -8.9974804260E-04 + -1.1683978097E-02 -2.0872046163E-03 2.4454699813E-03 + -1.1645929946E-02 7.7610254620E-04 1.3598051086E-03 + -1.1856340027E-02 -7.2315101163E-04 -1.0174057544E-04 + -1.4112585196E-02 2.2999841070E-03 -1.7154042443E-03 + -1.1601768413E-02 -2.0947537821E-03 7.0795443372E-04 + -1.3243930280E-02 1.6990288627E-03 5.0126083416E-04 + -1.4022519855E-02 -1.9932453005E-04 -1.0338092314E-03 + 2.5470811032E-03 -2.2067229914E-04 1.3383305708E-02 + -2.1248392165E-03 2.6732837479E-04 -1.3264615402E-02 +:ANGLES: + 90.000 89.999 90.000 +:VOLUME: 6.7440589793E+03 +:LATVEC_SCALE: + 1.8893724039E+01 1.8893259207E+01 1.8892825314E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -6.6541303120E-06 9.9999999998E-01 0.0000000000E+00 + 1.1856886505E-05 -2.5579567856E-06 9.9999999993E-01 +:STRIO: + 7.0532232766E-01 -8.6551429382E-02 1.4057903641E-01 + -8.6551429382E-02 7.2255301541E-01 -2.7405822979E-02 + 1.4057903641E-01 -2.7405822979E-02 4.6975361752E-01 +:STRESS: + 4.9132424761E+00 -6.8580922638E-03 2.9636085640E-03 + -6.8580922638E-03 5.5265595127E+00 5.2133380611E-03 + 2.9636085640E-03 5.2133380611E-03 5.8128008839E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2079201485E+00 -7.9693337118E-02 1.3761542785E-01 + -7.9693337118E-02 -4.8040064973E+00 -3.2619161040E-02 + 1.3761542785E-01 -3.2619161040E-02 -5.3430472664E+00 +:PRESIO: 6.3254298686E-01 +:PRES: -5.4175342909E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7849913040E+00 +:PRESIG: 6.6583472302E-01 +:MIND: +Al - Al: 6.1244898695E+00 +C - C: 6.2102353324E+00 +Al - C: 6.2329642604E+00 + + +:MDSTEP: 6 +:MDTM: 55.97 +:TWIST: 0 +:TEL: 2400 +:TIO: 2405.7366120581 +:TEN: -2.6051554547E+00 +:KEN: 1.0856383193E-02 +:KENIG: 1.1427771783E-02 +:FEN: -2.6160118379E+00 +:UEN: -2.6088684668E+00 +:TSEN: -7.1433711128E-03 +:NPT_NP_HAMIL: 6.5197931161E-05 +:SNOSE[0]: 1.0102181536E+00 +:SNOSE[1]: 1.1694594099E-04 +:R: + 1.8889140396E+01 1.4226155338E-01 9.0827498084E-02 + 6.4522991550E-03 1.8858560524E+01 6.4035434403E+00 + 1.3907747509E-01 1.8797351038E+01 1.2529954160E+01 + 1.8830704070E+01 6.2686475373E+00 1.8797977052E+01 + 6.5547880648E-02 6.3806365381E+00 6.2899559258E+00 + 1.8863579703E+01 6.3736457843E+00 1.2581425780E+01 + 1.8734394715E+01 1.2471612879E+01 5.4877567559E-02 + 1.5459293190E-02 1.2621314995E+01 6.3778595210E+00 + 1.0082571862E-01 1.2496206194E+01 1.2623896673E+01 + 6.2063225903E+00 1.8885832280E+01 1.8762942735E+01 + 6.3034715057E+00 3.7158260287E-03 6.2331365185E+00 + 6.3113872037E+00 1.8792893703E+01 1.2683764583E+01 + 6.4041763066E+00 6.2874792905E+00 7.8706243783E-02 + 6.4530123138E+00 6.3687899911E+00 6.2862875089E+00 + 6.1468054724E+00 6.4151630157E+00 1.2531901648E+01 + 6.3037394225E+00 1.2421058418E+01 1.8878532464E+01 + 6.2244586613E+00 1.2717464836E+01 6.2911176038E+00 + 6.2611255346E+00 1.2596076877E+01 1.2504891549E+01 + 1.2636578783E+01 3.7607208475E-02 7.2865493115E-02 + 1.2518936096E+01 1.8882715841E+01 6.2545556443E+00 +:V: + -2.0545883343E-05 6.8882800356E-04 4.3825543902E-04 + 2.6808307194E-05 -1.5932539313E-04 5.1406144477E-04 + 6.9244161493E-04 -4.5328143985E-04 -3.0939678189E-04 + -2.7095569402E-04 -1.3825559698E-04 -4.4581219848E-04 + 3.4002955233E-04 4.0286845578E-04 -3.1827838104E-05 + -1.0773370794E-04 3.7241433685E-04 -5.8500881847E-05 + -7.3218982640E-04 -5.9235844064E-04 2.6392434889E-04 + 1.0197831705E-04 1.3179821057E-04 3.8916205685E-04 + 5.1268691306E-04 -4.7169492362E-04 1.4416037819E-04 + -4.3646703858E-04 -2.2886582885E-05 -6.1640588487E-04 + 3.8902152306E-05 1.5514185981E-05 -3.0781466090E-04 + 4.2981036239E-05 -4.7592289974E-04 4.3694825540E-04 + 4.8898146961E-04 -4.4785865220E-05 3.8055156217E-04 + 7.2266025122E-04 3.4325822107E-04 -5.1000958488E-05 + -7.5297132124E-04 5.7156218447E-04 -2.9998940614E-04 + 5.3100681584E-06 -8.3477643383E-04 -5.6631289756E-05 + -3.7734831657E-04 5.9558520104E-04 -2.6711360866E-05 + -2.0338132699E-04 9.1451338622E-06 -4.2854218842E-04 + 2.1174539830E-04 1.7976897694E-04 4.1184785682E-04 + -3.7165906897E-04 -3.9787464198E-05 -2.6455133518E-04 +:F: + -3.4878688897E-03 3.8120756081E-03 1.1986725874E-03 + -1.7071853837E-03 -1.6965730484E-03 1.2259392843E-03 + 1.1716423847E-02 -1.7655629069E-03 -2.1445082294E-03 + 1.1316973313E-02 -1.2947862114E-03 -6.8050349768E-04 + 1.1979954879E-02 1.0385013002E-03 9.8392351977E-04 + 1.4331211288E-02 3.0629206444E-03 3.8009965154E-04 + 1.0981054008E-02 -2.7561825905E-03 1.4064490342E-04 + 1.3547348292E-02 7.1501832833E-04 7.9891566444E-05 + 1.4002336906E-02 -1.0171426618E-03 -5.9083240096E-04 + -5.4920289143E-04 1.9456664359E-03 -2.3747772782E-03 + 5.4271647808E-03 -1.7017915092E-03 -1.0399914577E-03 + -1.1666124040E-02 -2.6007841926E-03 3.0129188443E-03 + -1.1414328576E-02 1.0210317620E-03 1.6645927566E-03 + -1.1693571666E-02 -8.4774655172E-04 -1.1283914237E-04 + -1.4306722256E-02 2.8799982479E-03 -2.1273608750E-03 + -1.1382294857E-02 -2.6732419430E-03 8.5442468192E-04 + -1.3407514703E-02 2.0410935180E-03 6.4623197414E-04 + -1.4195291116E-02 -2.3743484559E-04 -1.2745774748E-03 + 3.1589273989E-03 -2.6576698632E-04 1.3855201001E-02 + -2.6512903320E-03 3.4070760262E-04 -1.3697150415E-02 +:ANGLES: + 90.001 89.999 90.000 +:VOLUME: 6.7419078564E+03 +:LATVEC_SCALE: + 1.8891946740E+01 1.8891244056E+01 1.8890590836E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.0047370983E-05 9.9999999995E-01 0.0000000000E+00 + 1.7827713988E-05 -3.8840074977E-06 9.9999999983E-01 +:STRIO: + 7.0357804726E-01 -8.8906706235E-02 1.4115462749E-01 + -8.8906706235E-02 7.2047323768E-01 -2.6902430016E-02 + 1.4115462749E-01 -2.6902430016E-02 4.7099579754E-01 +:STRESS: + 4.9008797190E+00 -8.7106146590E-03 2.2222403947E-03 + -8.7106146590E-03 5.5215112337E+00 7.5995667225E-03 + 2.2222403947E-03 7.5995667225E-03 5.8166069018E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1973016717E+00 -8.0196091576E-02 1.3893238709E-01 + -8.0196091576E-02 -4.8010379961E+00 -3.4501996738E-02 + 1.3893238709E-01 -3.4501996738E-02 -5.3456111042E+00 +:PRESIO: 6.3168236083E-01 +:PRES: -5.4129992848E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7813169240E+00 +:PRESIG: 6.6492880087E-01 +:MIND: +Al - Al: 6.0807962608E+00 +C - C: 6.1830549508E+00 +Al - C: 6.2155138101E+00 + + +:MDSTEP: 7 +:MDTM: 56.18 +:TWIST: 0 +:TEL: 2400 +:TIO: 2401.73918788961 +:TEN: -2.6052962618E+00 +:KEN: 1.0838343991E-02 +:KENIG: 1.1408783149E-02 +:FEN: -2.6161346058E+00 +:UEN: -2.6090141552E+00 +:TSEN: -7.1204506225E-03 +:NPT_NP_HAMIL: 8.4913941441E-05 +:SNOSE[0]: 1.0158450689E+00 +:SNOSE[1]: 1.2745946681E-04 +:R: + 1.8886088616E+01 1.7070365130E-01 1.0890060072E-01 + 7.4958705509E-03 1.8849522878E+01 6.4238394771E+00 + 1.6782176077E-01 1.8776192778E+01 1.2515372344E+01 + 1.8817702854E+01 6.2620874663E+00 1.8776901473E+01 + 7.9783859443E-02 6.3964288961E+00 6.2877619135E+00 + 1.8857309995E+01 6.3882084455E+00 1.2577222518E+01 + 1.8702224755E+01 1.2445540006E+01 6.5751380855E-02 + 1.9890214784E-02 1.2625123472E+01 6.3929908995E+00 + 1.2223084316E-01 1.2475113640E+01 1.2628024417E+01 + 6.1876740051E+00 1.8882458273E+01 1.8734810774E+01 + 6.3044984790E+00 4.3151959448E-03 6.2195391178E+00 + 6.3122548216E+00 1.8770787929E+01 1.2700015204E+01 + 6.4233831671E+00 6.2848404844E+00 9.4410540096E-02 + 6.4818858942E+00 6.3820939783E+00 6.2832846859E+00 + 6.1148846229E+00 6.4379264411E+00 1.2517707633E+01 + 6.3031308972E+00 1.2384969839E+01 1.8873514382E+01 + 6.2079575727E+00 1.2740402090E+01 6.2891284815E+00 + 6.2518233406E+00 1.2594806174E+01 1.2485417096E+01 + 1.2643996163E+01 4.5002229746E-02 9.0371047200E-02 + 1.2502058381E+01 1.8878645571E+01 6.2422235101E+00 +:V: + -2.3393552663E-05 6.8860396378E-04 4.3696873016E-04 + 2.5353370029E-05 -1.6001861065E-04 5.1243455367E-04 + 6.9849415495E-04 -4.5246063904E-04 -3.0969739971E-04 + -2.6011292032E-04 -1.3866821273E-04 -4.4403635577E-04 + 3.4818791044E-04 4.0165839053E-04 -3.0744131359E-05 + -9.5051570742E-05 3.7321450531E-04 -5.7830687476E-05 + -7.1913699017E-04 -5.9172531812E-04 2.6262164271E-04 + 1.1286729375E-04 1.3172260847E-04 3.8714522886E-04 + 5.2168988615E-04 -4.7007286736E-04 1.4282828623E-04 + -4.3485049473E-04 -2.0968766151E-05 -6.1527605902E-04 + 4.3435056745E-05 1.3871062486E-05 -3.0708327582E-04 + 3.2976111883E-05 -4.7574012694E-04 4.3734129195E-04 + 4.7685848198E-04 -4.3586912929E-05 3.8001521873E-04 + 7.0900332339E-04 3.4064067292E-04 -5.0831854026E-05 + -7.6095596123E-04 5.7112019102E-04 -3.0031587964E-04 + -4.1701621860E-06 -8.3273880369E-04 -5.5549141849E-05 + -3.8660461844E-04 5.9421072943E-04 -2.5963081157E-05 + -2.1424621646E-04 8.8844702269E-06 -4.2739396713E-04 + 2.1711006327E-04 1.7825773626E-04 4.3620017805E-04 + -3.7512897301E-04 -3.8860241504E-05 -2.8935986443E-04 +:F: + -3.5721451910E-03 4.5443624745E-03 1.3710634964E-03 + -1.4178607892E-03 -2.0136395795E-03 1.5121043700E-03 + 1.1689042192E-02 -2.1337697260E-03 -2.5418515697E-03 + 1.1045602234E-02 -1.4714572695E-03 -8.2669097495E-04 + 1.1887474476E-02 1.2714385296E-03 1.1956024972E-03 + 1.4531756312E-02 3.6534311137E-03 4.6218842446E-04 + 1.0683238347E-02 -3.3718028602E-03 1.3951231236E-04 + 1.3752333148E-02 8.0481732070E-04 1.2048412084E-04 + 1.4114996645E-02 -1.2069443134E-03 -7.1999959187E-04 + -1.2426948196E-03 2.3377541581E-03 -2.8727930345E-03 + 5.8902653882E-03 -2.0177609079E-03 -1.1775631928E-03 + -1.1648198513E-02 -3.1062880850E-03 3.5522033920E-03 + -1.1179948990E-02 1.2559686959E-03 1.9635900094E-03 + -1.1535016546E-02 -9.7263682306E-04 -1.2938513657E-04 + -1.4491602966E-02 3.4501771556E-03 -2.5285225226E-03 + -1.1168399413E-02 -3.2406139151E-03 1.0010829637E-03 + -1.3561969230E-02 2.3714120668E-03 7.8584562250E-04 + -1.4359838224E-02 -2.6429411424E-04 -1.5070248416E-03 + 3.7575677870E-03 -3.0700484189E-04 1.4369614253E-02 + -3.1746018478E-03 4.1685092094E-04 -1.4169460597E-02 +:ANGLES: + 90.001 89.999 90.000 +:VOLUME: 6.7393103385E+03 +:LATVEC_SCALE: + 1.8889801929E+01 1.8888809756E+01 1.8887890628E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.4167887209E-05 9.9999999990E-01 0.0000000000E+00 + 2.5059070297E-05 -5.5221462738E-06 9.9999999967E-01 +:STRIO: + 7.0197436811E-01 -9.1226297193E-02 1.4187277811E-01 + -9.1226297193E-02 7.1830118373E-01 -2.6418652581E-02 + 1.4187277811E-01 -2.6418652581E-02 4.7235186955E-01 +:STRESS: + 4.8875000407E+00 -1.0603122093E-02 8.1475097781E-04 + -1.0603122093E-02 5.5146167904E+00 1.0350341446E-02 + 8.1475097781E-04 1.0350341446E-02 5.8205449587E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1855256726E+00 -8.0623175100E-02 1.4105802713E-01 + -8.0623175100E-02 -4.7963156067E+00 -3.6768994027E-02 + 1.4105802713E-01 -3.6768994027E-02 -5.3481930892E+00 +:PRESIO: 6.3087580713E-01 +:PRES: -5.4075539300E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7766781228E+00 +:PRESIG: 6.6407979698E-01 +:MIND: +Al - Al: 6.0371142291E+00 +C - C: 6.1538412151E+00 +Al - C: 6.1976187133E+00 + + +:MDSTEP: 8 +:MDTM: 52.63 +:TWIST: 0 +:TEL: 2400 +:TIO: 2400.81760452533 +:TEN: -2.6054455367E+00 +:KEN: 1.0834185156E-02 +:KENIG: 1.1404405428E-02 +:FEN: -2.6162797218E+00 +:UEN: -2.6091858886E+00 +:TSEN: -7.0938332631E-03 +:NPT_NP_HAMIL: 8.3237486646E-05 +:SNOSE[0]: 1.0216834387E+00 +:SNOSE[1]: 1.2855143188E-04 +:R: + 1.8882544531E+01 1.9913845451E-01 1.2691628564E-01 + 8.4786412240E-03 1.8840024374E+01 6.4439063761E+00 + 1.9680766849E-01 1.8754637744E+01 1.2500459672E+01 + 1.8804793609E+01 6.2553608086E+00 1.8755428880E+01 + 9.4353117891E-02 6.4120246969E+00 6.2854583800E+00 + 1.8851205822E+01 6.4026619525E+00 1.2572732503E+01 + 1.8670215244E+01 1.2419207003E+01 7.6567041484E-02 + 2.4771167302E-02 1.2628641456E+01 6.4078749140E+00 + 1.4400916217E-01 1.2453802989E+01 1.2631775808E+01 + 6.1689717205E+00 1.8878737135E+01 1.8706251943E+01 + 6.3056031787E+00 4.8390461717E-03 6.2058162629E+00 + 6.3125879393E+00 1.8748256931E+01 1.2715967238E+01 + 6.4419584732E+00 6.2821134497E+00 1.1009151057E-01 + 6.5100678579E+00 6.3951381209E+00 6.2801310116E+00 + 6.0825286849E+00 6.4605261134E+00 1.2503181471E+01 + 6.3020261163E+00 1.2348677283E+01 1.8868069220E+01 + 6.1909515170E+00 1.2762992364E+01 6.2870146778E+00 + 6.2419554104E+00 1.2593235237E+01 1.2465676365E+01 + 1.2651406018E+01 5.2330501310E-02 1.0889357297E-01 + 1.2484767286E+01 1.8874187968E+01 6.2286963694E+00 +:V: + -2.6296333734E-05 6.8887945789E-04 4.3576666356E-04 + 2.4144641185E-05 -1.6094517189E-04 5.1097334749E-04 + 7.0437775712E-04 -4.5188402403E-04 -3.1027703744E-04 + -2.4952008612E-04 -1.3919892099E-04 -4.4232335939E-04 + 3.5617134197E-04 4.0058485448E-04 -2.9486652930E-05 + -8.2258404055E-05 3.7444042487E-04 -5.7085755989E-05 + -7.0629032189E-04 -5.9151990087E-04 2.6128510691E-04 + 1.2384962113E-04 1.3170191433E-04 3.8511521899E-04 + 5.3065054395E-04 -4.6854163621E-04 1.4137176338E-04 + -4.3374742363E-04 -1.8730123296E-05 -6.1446545212E-04 + 4.8326485735E-05 1.1973956612E-05 -3.0642362278E-04 + 2.3035779888E-05 -4.7590486985E-04 4.3810433319E-04 + 4.6492460693E-04 -4.2196069942E-05 3.7967152964E-04 + 6.9544186784E-04 3.3788128446E-04 -5.0672704749E-05 + -7.6892781919E-04 5.7106515033E-04 -3.0092510431E-04 + -1.3420629379E-05 -8.3105417499E-04 -5.4341684482E-05 + -3.9587507634E-04 5.9302416160E-04 -2.5099662647E-05 + -2.2515196450E-04 8.6059864727E-06 -4.2637840140E-04 + 2.2352490588E-04 1.7665359639E-04 4.6136430780E-04 + -3.7950292438E-04 -3.7786168204E-05 -3.1491802567E-04 +:F: + -3.6654470668E-03 5.2529389053E-03 1.5402743001E-03 + -1.1293978711E-03 -2.3209679521E-03 1.7844957048E-03 + 1.1652944721E-02 -2.5041753783E-03 -2.9229209051E-03 + 1.0766172582E-02 -1.6323533919E-03 -9.6743728751E-04 + 1.1799360899E-02 1.4946010944E-03 1.4025553492E-03 + 1.4727289333E-02 4.2257735116E-03 5.4600831080E-04 + 1.0392745306E-02 -3.9836204714E-03 1.3584349955E-04 + 1.3955111884E-02 8.9288876498E-04 1.6176286471E-04 + 1.4213900727E-02 -1.3855458427E-03 -8.5158570541E-04 + -1.9150987911E-03 2.7293483553E-03 -3.3442929041E-03 + 6.3582878799E-03 -2.3243794992E-03 -1.3117994729E-03 + -1.1631111462E-02 -3.6014866690E-03 4.0585080563E-03 + -1.0944742711E-02 1.4779546065E-03 2.2552020612E-03 + -1.1381095699E-02 -1.0970034368E-03 -1.5096382526E-04 + -1.4664469944E-02 4.0077684992E-03 -2.9172451979E-03 + -1.0960115002E-02 -3.7932371282E-03 1.1480351905E-03 + -1.3706832110E-02 2.6895216132E-03 9.1954980222E-04 + -1.4515262258E-02 -2.7965217303E-04 -1.7306744397E-03 + 4.3417511746E-03 -3.4444072671E-04 1.4928957876E-02 + -3.6939915915E-03 4.9606731874E-04 -1.4684273278E-02 +:ANGLES: + 90.001 89.998 90.000 +:VOLUME: 6.7362583491E+03 +:LATVEC_SCALE: + 1.8887283343E+01 1.8885948409E+01 1.8884715245E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.9034640321E-05 9.9999999982E-01 0.0000000000E+00 + 3.3596260522E-05 -7.4990272936E-06 9.9999999941E-01 +:STRIO: + 7.0138865624E-01 -9.3621088926E-02 1.4291888193E-01 + -9.3621088926E-02 7.1693608888E-01 -2.5990415772E-02 + 1.4291888193E-01 -2.5990415772E-02 4.7443360840E-01 +:STRESS: + 4.8730947496E+00 -1.2527324667E-02 -1.2887726087E-03 + -1.2527324667E-02 5.5058785381E+00 1.3430074704E-02 + -1.2887726087E-03 1.3430074704E-02 5.8246676088E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1717060934E+00 -8.1093764259E-02 1.4420765454E-01 + -8.1093764259E-02 -4.7889424493E+00 -3.9420490476E-02 + 1.4420765454E-01 -3.9420490476E-02 -5.3502340005E+00 +:PRESIO: 6.3091945117E-01 +:PRES: -5.4012136322E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7702941810E+00 +:PRESIG: 6.6412573807E-01 +:MIND: +Al - Al: 5.9934265289E+00 +C - C: 6.1225481410E+00 +Al - C: 6.1792292892E+00 + + +:MDSTEP: 9 +:MDTM: 49.16 +:TWIST: 0 +:TEL: 2400 +:TIO: 2403.60926058382 +:TEN: -2.6055997545E+00 +:KEN: 1.0846783081E-02 +:KENIG: 1.1417666401E-02 +:FEN: -2.6164465375E+00 +:UEN: -2.6093830120E+00 +:TSEN: -7.0635255887E-03 +:NPT_NP_HAMIL: 7.2158888479E-05 +:SNOSE[0]: 1.0275881804E+00 +:SNOSE[1]: 1.3320212083E-04 +:R: + 1.8878500042E+01 2.2758679744E-01 1.4487832287E-01 + 9.4108508604E-03 1.8830047971E+01 6.4637481421E+00 + 2.2602920369E-01 1.8732667779E+01 1.2485198740E+01 + 1.8791960627E+01 6.2484598731E+00 1.8733547485E+01 + 1.0924906225E-01 6.4274272018E+00 6.2830493881E+00 + 1.8845266272E+01 6.4170211016E+00 1.2567952832E+01 + 1.8638350956E+01 1.2392590893E+01 8.7323320182E-02 + 3.0106134758E-02 1.2631866283E+01 6.4225083612E+00 + 1.6615973651E-01 1.2432265005E+01 1.2635139836E+01 + 6.1501930710E+00 1.8874674252E+01 1.8677244140E+01 + 6.3067988758E+00 5.2769245451E-03 6.1919618398E+00 + 6.3123878576E+00 1.8725278465E+01 1.2731629716E+01 + 6.4599087841E+00 6.2793033877E+00 1.2575725267E-01 + 6.5375613669E+00 6.4079143436E+00 6.2768229684E+00 + 6.0497361092E+00 6.4829755428E+00 1.2488305546E+01 + 6.3004334637E+00 1.2312160230E+01 1.8862193153E+01 + 6.1734378552E+00 1.2785238772E+01 6.2847778261E+00 + 6.2315185478E+00 1.2591358353E+01 1.2445657753E+01 + 1.2658847549E+01 5.9588514478E-02 1.2846831323E-01 + 1.2467021433E+01 1.8869341742E+01 6.2139387686E+00 +:V: + -2.9264483114E-05 6.8972922968E-04 4.3470934140E-04 + 2.3184331146E-05 -1.6211834788E-04 5.0973824331E-04 + 7.1018560496E-04 -4.5161705362E-04 -3.1116443267E-04 + -2.3922078416E-04 -1.3985296680E-04 -4.4073261310E-04 + 3.6403377443E-04 3.9969684043E-04 -2.8065098058E-05 + -6.9374521359E-05 3.7612718686E-04 -5.6273399014E-05 + -6.9374716478E-04 -5.9182091208E-04 2.5995061718E-04 + 1.3493771027E-04 1.3175325467E-04 3.8312912825E-04 + 5.3963162991E-04 -4.6715884526E-04 1.3981011090E-04 + -4.3319994116E-04 -1.6176278974E-05 -6.1403653563E-04 + 5.3584254983E-05 9.8348267614E-06 -3.0587659641E-04 + 1.3164947714E-05 -4.7647492224E-04 4.3926845413E-04 + 4.5324896298E-04 -4.0632627473E-05 3.7956760072E-04 + 6.8207471011E-04 3.3503055044E-04 -5.0534793022E-05 + -7.7698480210E-04 5.7146613737E-04 -3.0184789377E-04 + -2.2446890053E-05 -8.2982714422E-04 -5.3017728284E-05 + -4.0520609294E-04 5.9209980384E-04 -2.4130337219E-05 + -2.3612031727E-04 8.3209021215E-06 -4.2554900183E-04 + 2.3098570696E-04 1.7498993164E-04 4.8748366932E-04 + -3.8482142733E-04 -3.6565796466E-05 -3.4134411539E-04 +:F: + -3.7675375368E-03 5.9330641789E-03 1.7062612768E-03 + -8.4054848439E-04 -2.6178629236E-03 2.0401112203E-03 + 1.1606578532E-02 -2.8758783730E-03 -3.2857282780E-03 + 1.0479440030E-02 -1.7754785713E-03 -1.1027639257E-03 + 1.1715212118E-02 1.7076214200E-03 1.6043034434E-03 + 1.4916485558E-02 4.7773100562E-03 6.3175639299E-04 + 1.0110420042E-02 -4.5888843643E-03 1.2911283564E-04 + 1.4154609979E-02 9.7885774387E-04 2.0465871112E-04 + 1.4298183071E-02 -1.5518393090E-03 -9.8570022344E-04 + -2.5659374593E-03 3.1199738925E-03 -3.7834238431E-03 + 6.8309499656E-03 -2.6203787540E-03 -1.4418736850E-03 + -1.1614249789E-02 -4.0856165095E-03 4.5262220068E-03 + -1.0709816307E-02 1.6847302347E-03 2.5380785089E-03 + -1.1232634164E-02 -1.2211866085E-03 -1.7702249426E-04 + -1.4822682879E-02 4.5512112845E-03 -3.2924621403E-03 + -1.0757120182E-02 -4.3276314942E-03 1.2947147633E-03 + -1.3841237464E-02 2.9947497485E-03 1.0476202603E-03 + -1.4660985805E-02 -2.8304798334E-04 -1.9451350850E-03 + 4.9094864905E-03 -3.7827985835E-04 1.5535834394E-02 + -4.2086157155E-03 5.7856618997E-04 -1.5244564138E-02 +:ANGLES: + 90.001 89.998 90.001 +:VOLUME: 6.7327445049E+03 +:LATVEC_SCALE: + 1.8884385304E+01 1.8882652781E+01 1.8881055745E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -2.4666584280E-05 9.9999999970E-01 0.0000000000E+00 + 4.3493498787E-05 -9.8452296055E-06 9.9999999901E-01 +:STRIO: + 7.0199840068E-01 -9.6118548898E-02 1.4434090960E-01 + -9.6118548898E-02 7.1655831835E-01 -2.5626252192E-02 + 1.4434090960E-01 -2.5626252192E-02 4.7739150855E-01 +:STRESS: + 4.8576156964E+00 -1.4485320068E-02 -4.1282391767E-03 + -1.4485320068E-02 5.4952531023E+00 1.6793028399E-02 + -4.1282391767E-03 1.6793028399E-02 5.8289523539E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1556172957E+00 -8.1633228830E-02 1.4846914877E-01 + -8.1633228830E-02 -4.7786947840E+00 -4.2419280590E-02 + 1.4846914877E-01 -4.2419280590E-02 -5.3515608454E+00 +:PRESIO: 6.3198274253E-01 +:PRES: -5.3939403842E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7619576417E+00 +:PRESIG: 6.6524499214E-01 +:MIND: +Al - Al: 5.9497022723E+00 +C - C: 6.0891152671E+00 +Al - C: 6.1602904686E+00 + + +:MDSTEP: 10 +:MDTM: 54.41 +:TWIST: 0 +:TEL: 2400 +:TIO: 2407.96231945583 +:TEN: -2.6057679482E+00 +:KEN: 1.0866427158E-02 +:KENIG: 1.1438344376E-02 +:FEN: -2.6166343754E+00 +:UEN: -2.6096047810E+00 +:TSEN: -7.0295943493E-03 +:NPT_NP_HAMIL: 6.4096912936E-05 +:SNOSE[0]: 1.0340108127E+00 +:SNOSE[1]: 1.5130856119E-04 +:R: + 1.8873946461E+01 2.5606421359E-01 1.6278772552E-01 + 1.0302618556E-02 1.8819577415E+01 6.4833647782E+00 + 2.5547579115E-01 1.8710266823E+01 1.2469574141E+01 + 1.8779189016E+01 6.2413781868E+00 1.8711247453E+01 + 1.2446302111E-01 6.4426366519E+00 6.2805386252E+00 + 1.8839490045E+01 6.4312973065E+00 1.2562880375E+01 + 1.8606620465E+01 1.2365672218E+01 9.8017329338E-02 + 3.5898039510E-02 1.2634793972E+01 6.4368854941E+00 + 1.8867787090E-01 1.2410493256E+01 1.2638103998E+01 + 6.1313189076E+00 1.8870274283E+01 1.8647769273E+01 + 6.3080984224E+00 5.6187519906E-03 6.1779714435E+00 + 6.3116558891E+00 1.8701832995E+01 1.2747006956E+01 + 6.4772378534E+00 6.2764149506E+00 1.4141321044E-01 + 6.5643653414E+00 6.4204123945E+00 6.2733568890E+00 + 6.0165106607E+00 6.5052839306E+00 1.2473064025E+01 + 6.2983614203E+00 1.2275403401E+01 1.8855881709E+01 + 6.1554167932E+00 1.2807139933E+01 6.2824191706E+00 + 6.2205114654E+00 1.2589169727E+01 1.2425351975E+01 + 1.2666356582E+01 6.6772022393E-02 1.4913063795E-01 + 1.2448782126E+01 1.8864105405E+01 6.1979140861E+00 +:V: + -3.2291407141E-05 6.9082471967E-04 4.3360429618E-04 + 2.2462097198E-05 -1.6345721700E-04 5.0849149088E-04 + 7.1559948060E-04 -4.5146269856E-04 -3.1220603910E-04 + -2.2911766006E-04 -1.4055391822E-04 -4.3906806551E-04 + 3.7161910411E-04 3.9881140030E-04 -2.6473043633E-05 + -5.6379165224E-05 3.7808987697E-04 -5.5368069115E-05 + -6.8120005787E-04 -5.9236108051E-04 2.5850292046E-04 + 1.4606658499E-04 1.3181716842E-04 3.8102231674E-04 + 5.4838354771E-04 -4.6571021186E-04 1.3808157815E-04 + -4.3299864297E-04 -1.3303551524E-05 -6.1369121022E-04 + 5.9185461326E-05 7.4609302514E-06 -3.0530514287E-04 + 3.3596535739E-06 -4.7723148345E-04 4.4060604885E-04 + 4.4163534945E-04 -3.8893915026E-05 3.7952927170E-04 + 6.6860263218E-04 3.3194433850E-04 -5.0399622767E-05 + -7.8477392135E-04 5.7205942899E-04 -3.0293918299E-04 + -3.1242801408E-05 -8.2867842343E-04 -5.1555560288E-05 + -4.1441013071E-04 5.9116774837E-04 -2.3049795831E-05 + -2.4703684810E-04 8.0363761498E-06 -4.2471250310E-04 + 2.3935141013E-04 1.7319784259E-04 5.1442662976E-04 + -3.9090107184E-04 -3.5177732805E-05 -3.6856702396E-04 +:F: + -3.8780294274E-03 6.5806746077E-03 1.8678762411E-03 + -5.4990978225E-04 -2.9040977708E-03 2.2757009819E-03 + 1.1549547124E-02 -3.2482419655E-03 -3.6272502814E-03 + 1.0186274015E-02 -1.9009803538E-03 -1.2330536924E-03 + 1.1634780856E-02 1.9104086615E-03 1.8005736272E-03 + 1.5098264408E-02 5.3053384418E-03 7.1962927323E-04 + 9.8375849194E-03 -5.1832907915E-03 1.1906475212E-04 + 1.4349999164E-02 1.0625348506E-03 2.4960225462E-04 + 1.4366251090E-02 -1.7045322111E-03 -1.1218817464E-03 + -3.1949124667E-03 3.5093168898E-03 -4.1847848557E-03 + 7.3078584521E-03 -2.9039964373E-03 -1.5671411052E-03 + -1.1597681935E-02 -4.5582576739E-03 4.9505630808E-03 + -1.0476171828E-02 1.8742187623E-03 2.8105432639E-03 + -1.1090758807E-02 -1.3451114312E-03 -2.0703358434E-04 + -1.4964364111E-02 5.0781897807E-03 -3.6527272739E-03 + -1.0559565846E-02 -4.8406327682E-03 1.4408591272E-03 + -1.3964761663E-02 3.2854877314E-03 1.1707772880E-03 + -1.4795242830E-02 -2.7290167185E-04 -2.1506718598E-03 + 5.4586552555E-03 -4.0897331538E-04 1.6192314886E-02 + -4.7178165874E-03 6.6484666478E-04 -1.5852960377E-02 +:ANGLES: + 90.002 89.997 90.001 +:VOLUME: 6.7287607745E+03 +:LATVEC_SCALE: + 1.8881101612E+01 1.8878915040E+01 1.8876902280E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -3.1085113563E-05 9.9999999952E-01 0.0000000000E+00 + 5.4819017913E-05 -1.2595998629E-05 9.9999999842E-01 +:STRIO: + 7.0316598247E-01 -9.8635472439E-02 1.4602096981E-01 + -9.8635472439E-02 7.1651514736E-01 -2.5304912433E-02 + 1.4602096981E-01 -2.5304912433E-02 4.8082527651E-01 +:STRESS: + 4.8410711130E+00 -1.6482434708E-02 -7.7370808798E-03 + -1.6482434708E-02 5.4827192627E+00 2.0388558144E-02 + -7.7370808798E-03 2.0388558144E-02 5.8334258597E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1379051306E+00 -8.2153037731E-02 1.5375805069E-01 + -8.2153037731E-02 -4.7662041154E+00 -4.5693470577E-02 + 1.5375805069E-01 -4.5693470577E-02 -5.3526005832E+00 +:PRESIO: 6.3350213545E-01 +:PRES: -5.3857387452E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7522366097E+00 +:PRESIG: 6.6684435310E-01 +:MIND: +Al - Al: 5.9059198957E+00 +C - C: 6.0534826297E+00 +Al - C: 6.1407508432E+00 diff --git a/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.refout b/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.refout new file mode 100644 index 00000000..8aa47b6b --- /dev/null +++ b/tests/Al18C2_NPTNP_full_flex/high_accuracy/Al18C2_NPTNP_full_flex.refout @@ -0,0 +1,655 @@ +*************************************************************************** +* SPARC (version December 03, 2025) * +* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * +* Distributed under GNU General Public License 3 (GPL) * +* Start time: Sun Apr 5 13:01:27 2026 * +*************************************************************************** + Input parameters +*************************************************************************** +LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 +LATVEC: +1.000000000000000 0.000000000000000 0.000000000000000 +0.000000000000000 1.000000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 +WARNING: This system is cuboidal. To get the best performance, please align the lattice vectors onto standard cartesian coordinate. +FD_GRID: 126 126 126 +FD_ORDER: 12 +BC: P P P +KPOINT_GRID: 1 1 1 +KPOINT_SHIFT: 0 0 0 +SPIN_TYP: 0 +ELEC_TEMP_TYPE: Fermi-Dirac +ELEC_TEMP: 2400 +EXCHANGE_CORRELATION: GGA_PBE +HUBBARD_FLAG: 0 +NSTATES: 80 +CHEB_DEGREE: 42 +CHEFSI_BOUND_FLAG: 0 +CALC_STRESS: 1 +TWTIME: 1E+09 +MD_FLAG: 1 +MD_METHOD: NPT_NP +MD_TIMESTEP: 1 +MD_NSTEP: 10 +ION_VEL_DSTR: 2 +ION_VEL_DSTR_RAND: 0 +ION_TEMP: 2400 +NPT_SCALE_VECS: 1 2 3 +NPT_SCALE_CONSTRAINTS: none +NPT_NP_ANGLES: 1 +NPT_NP_QMASS: 2000 +NPT_NP_BMASS: 0.5 +TARGET_STRESS: 0.1 0.1 0.1 0 0 0 GPa +MAXIT_SCF: 100 +MINIT_SCF: 2 +MAXIT_POISSON: 3000 +TOL_SCF: 1.00E-06 +POISSON_SOLVER: AAR +TOL_POISSON: 1.00E-08 +TOL_LANCZOS: 1.00E-02 +TOL_PSEUDOCHARGE: 1.00E-09 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +TOL_PRECOND: 2.25E-05 +PRECOND_KERKER_KTF: 1 +PRECOND_KERKER_THRESH: 0 +MIXING_PARAMETER: 1 +MIXING_HISTORY: 7 +PULAY_FREQUENCY: 1 +PULAY_RESTART: 0 +REFERENCE_CUTOFF: 0.5 +RHO_TRIGGER: 4 +NUM_CHEFSI: 1 +FIX_RAND: 0 +VERBOSITY: 1 +PRINT_FORCES: 1 +PRINT_ATOMS: 1 +PRINT_EIGEN: 0 +PRINT_DENSITY: 0 +PRINT_MDOUT: 1 +PRINT_VELS: 1 +PRINT_RESTART: 1 +PRINT_RESTART_FQ: 1 +PRINT_ENERGY_DENSITY: 0 +OUTPUT_FILE: Al18C2_NPTNP_full_flex +*************************************************************************** + Cell +*************************************************************************** +Lattice vectors (Bohr): +18.897259886000001 0.000000000000000 0.000000000000000 +0.000000000000000 18.897259886000001 0.000000000000000 +0.000000000000000 0.000000000000000 18.897259886000001 +Volume: 6.7483330373E+03 (Bohr^3) +Density: 7.5528236408E-02 (amu/Bohr^3), 8.4635982984E-01 (g/cc) +*************************************************************************** + Parallelization +*************************************************************************** +NP_SPIN_PARAL: 1 +NP_KPOINT_PARAL: 1 +NP_BAND_PARAL: 20 +NP_DOMAIN_PARAL: 5 1 2 +NP_DOMAIN_PHI_PARAL: 5 5 8 +EIG_SERIAL_MAXNS: 1500 +*************************************************************************** + Initialization +*************************************************************************** +Number of processors : 200 +Mesh spacing : 0.149978 (Bohr) +Number of symmetry adapted k-points: 1 +Output printed to : Al18C2_NPTNP_full_flex.out_01 +MD output printed to : Al18C2_NPTNP_full_flex.aimd_01 +Total number of atom types : 2 +Total number of atoms : 20 +Total number of electrons : 62 +Atom type 1 (valence electrons) : Al 3 +Pseudopotential : ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +Atomic mass : 26.9815385 +Pseudocharge radii of atom type 1 : 6.75 6.75 6.75 (x, y, z dir) +Number of atoms of type 1 : 18 +Atom type 2 (valence electrons) : C 4 +Pseudopotential : ../../../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 +Atomic mass : 12.011 +Pseudocharge radii of atom type 2 : 6.75 6.75 6.75 (x, y, z dir) +Number of atoms of type 2 : 2 +Estimated total memory usage : 8.99 GB +Estimated memory per processor : 46.01 MB +=================================================================== + Self Consistent Field (SCF#1) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.5848953063E+00 2.229E-01 13.892 +2 -2.6395032588E+00 6.082E-01 9.453 +3 -2.6182296075E+00 3.461E-01 4.038 +4 -2.6174092106E+00 2.434E-01 3.951 +5 -2.6177000197E+00 2.431E-01 4.009 +6 -2.6158333322E+00 7.722E-02 4.031 +7 -2.6159663502E+00 1.089E-01 3.981 +8 -2.6158608757E+00 7.448E-02 3.968 +9 -2.6157116485E+00 6.243E-03 3.825 +10 -2.6157155945E+00 9.273E-03 3.927 +11 -2.6157143292E+00 1.684E-03 3.880 +12 -2.6157146979E+00 6.812E-04 3.830 +13 -2.6157149067E+00 2.915E-04 3.816 +14 -2.6157150064E+00 2.736E-04 3.802 +15 -2.6157150349E+00 9.007E-05 3.747 +16 -2.6157150421E+00 3.747E-05 3.724 +17 -2.6157150419E+00 1.706E-05 3.711 +18 -2.6157150413E+00 1.423E-05 3.649 +19 -2.6157150424E+00 2.068E-05 3.665 +20 -2.6157150417E+00 3.994E-06 3.502 +21 -2.6157150426E+00 1.531E-06 3.600 +22 -2.6157150438E+00 1.059E-06 3.526 +23 -2.6157150417E+00 2.061E-06 3.579 +24 -2.6157150410E+00 5.087E-07 3.553 +Total number of SCF: 24 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157150410E+00 (Ha/atom) +Total free energy : -5.2314300819E+01 (Ha) +Band structure energy : -9.0955847178E+00 (Ha) +Exchange correlation energy : -2.0462213979E+01 (Ha) +Self and correction energy : -7.6945325391E+01 (Ha) +-Entropy*kb*T : -1.4408987944E-01 (Ha) +Fermi level : -2.8343985913E-02 (Ha) +RMS force : 1.0663892339E-02 (Ha/Bohr) +Maximum force : 1.3273835429E-02 (Ha/Bohr) +Time for force calculation : 0.084 (sec) +Pressure : -5.4252783696E+00 (GPa) +Maximum stress : 5.7978276865E+00 (GPa) +Time for stress calculation : 0.199 (sec) +MD step time : 108.265 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8969065122359 18.896860908859 18.8968176348752 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149975 (Bohr) +Mesh spacing in y-direction : 0.149975 (Bohr) +Mesh spacing in z direction : 0.149975 (Bohr) +=================================================================== + Self Consistent Field (SCF#2) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159404253E+00 3.755E-02 3.934 +2 -2.6165102938E+00 1.875E-01 3.970 +3 -2.6157891963E+00 5.310E-02 3.964 +4 -2.6159218016E+00 9.176E-02 3.847 +5 -2.6157320726E+00 3.537E-03 3.912 +6 -2.6157309552E+00 2.077E-03 3.907 +7 -2.6157310446E+00 1.026E-03 3.744 +8 -2.6157313297E+00 5.650E-04 3.844 +9 -2.6157315467E+00 3.355E-04 3.853 +10 -2.6157316820E+00 1.557E-04 3.818 +11 -2.6157317291E+00 1.002E-04 3.704 +12 -2.6157317364E+00 7.254E-05 3.686 +13 -2.6157317374E+00 5.102E-05 3.686 +14 -2.6157317383E+00 1.379E-05 3.658 +15 -2.6157317386E+00 7.972E-06 3.512 +16 -2.6157317384E+00 3.239E-06 3.635 +17 -2.6157317399E+00 1.928E-06 3.623 +18 -2.6157317418E+00 8.664E-07 3.540 +Total number of SCF: 18 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157317418E+00 (Ha/atom) +Total free energy : -5.2314634835E+01 (Ha) +Band structure energy : -9.0962765426E+00 (Ha) +Exchange correlation energy : -2.0462672512E+01 (Ha) +Self and correction energy : -7.6945325713E+01 (Ha) +-Entropy*kb*T : -1.4398192720E-01 (Ha) +Fermi level : -2.8366313157E-02 (Ha) +RMS force : 1.0677796533E-02 (Ha/Bohr) +Maximum force : 1.3506052038E-02 (Ha/Bohr) +Time for force calculation : 0.083 (sec) +Pressure : -5.4249317335E+00 (GPa) +Maximum stress : 5.8015346555E+00 (GPa) +Time for stress calculation : 0.197 (sec) +MD step time : 69.157 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8962001234827 18.8960625034823 18.8959327239391 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.14997 (Bohr) +Mesh spacing in y-direction : 0.149969 (Bohr) +Mesh spacing in z direction : 0.149968 (Bohr) +=================================================================== + Self Consistent Field (SCF#3) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159825962E+00 3.827E-02 4.072 +2 -2.6165907636E+00 1.910E-01 3.895 +3 -2.6158301058E+00 5.420E-02 3.967 +4 -2.6159640956E+00 9.263E-02 3.954 +5 -2.6157708262E+00 3.591E-03 3.943 +6 -2.6157696450E+00 2.154E-03 3.888 +7 -2.6157697186E+00 1.040E-03 3.879 +8 -2.6157700140E+00 5.744E-04 3.808 +9 -2.6157702418E+00 3.490E-04 3.846 +10 -2.6157703851E+00 1.605E-04 3.809 +11 -2.6157704351E+00 1.064E-04 3.754 +12 -2.6157704434E+00 7.562E-05 3.585 +13 -2.6157704441E+00 5.348E-05 3.592 +14 -2.6157704450E+00 1.380E-05 3.611 +15 -2.6157704454E+00 8.039E-06 3.629 +16 -2.6157704454E+00 3.263E-06 3.598 +17 -2.6157704466E+00 1.897E-06 3.477 +18 -2.6157704483E+00 7.740E-07 3.545 +Total number of SCF: 18 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157704483E+00 (Ha/atom) +Total free energy : -5.2315408966E+01 (Ha) +Band structure energy : -9.0970628918E+00 (Ha) +Exchange correlation energy : -2.0463872789E+01 (Ha) +Self and correction energy : -7.6945326814E+01 (Ha) +-Entropy*kb*T : -1.4380749464E-01 (Ha) +Fermi level : -2.8396293749E-02 (Ha) +RMS force : 1.0737043574E-02 (Ha/Bohr) +Maximum force : 1.3774762519E-02 (Ha/Bohr) +Time for force calculation : 0.083 (sec) +Pressure : -5.4235076112E+00 (GPa) +Maximum stress : 5.8052513783E+00 (GPa) +Time for stress calculation : 0.197 (sec) +MD step time : 69.189 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8951401727472 18.8948632026964 18.8946034340084 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149961 (Bohr) +Mesh spacing in y-direction : 0.149959 (Bohr) +Mesh spacing in z direction : 0.149957 (Bohr) +=================================================================== + Self Consistent Field (SCF#4) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6157143640E+00 3.542E-03 3.776 +2 -2.6158302226E+00 5.069E-03 3.793 +3 -2.6158323190E+00 9.547E-03 3.819 +4 -2.6158304077E+00 1.633E-03 3.705 +5 -2.6158304272E+00 1.796E-03 3.705 +6 -2.6158303782E+00 1.016E-04 3.709 +7 -2.6158303755E+00 4.868E-05 3.693 +8 -2.6158303761E+00 3.433E-05 3.719 +9 -2.6158303771E+00 2.073E-05 3.691 +10 -2.6158303772E+00 8.230E-06 3.660 +11 -2.6158303783E+00 5.904E-06 3.656 +12 -2.6158303782E+00 1.018E-05 3.606 +13 -2.6158303782E+00 3.464E-06 3.487 +14 -2.6158303802E+00 7.345E-07 3.540 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6158303802E+00 (Ha/atom) +Total free energy : -5.2316607603E+01 (Ha) +Band structure energy : -9.0979032146E+00 (Ha) +Exchange correlation energy : -2.0465825067E+01 (Ha) +Self and correction energy : -7.6945327853E+01 (Ha) +-Entropy*kb*T : -1.4356489410E-01 (Ha) +Fermi level : -2.8433762216E-02 (Ha) +RMS force : 1.0849166611E-02 (Ha/Bohr) +Maximum force : 1.4075221738E-02 (Ha/Bohr) +Time for force calculation : 0.083 (sec) +Pressure : -5.4210465110E+00 (GPa) +Maximum stress : 5.8090136232E+00 (GPa) +Time for stress calculation : 0.197 (sec) +MD step time : 52.813 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8937240391575 18.8932592067311 18.8928253138311 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.14995 (Bohr) +Mesh spacing in y-direction : 0.149947 (Bohr) +Mesh spacing in z direction : 0.149943 (Bohr) +=================================================================== + Self Consistent Field (SCF#5) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6157974770E+00 3.478E-03 3.841 +2 -2.6159103040E+00 2.838E-03 3.800 +3 -2.6159150603E+00 1.556E-02 3.821 +4 -2.6159110195E+00 1.943E-03 3.701 +5 -2.6159109661E+00 1.065E-03 9.156 +6 -2.6159109481E+00 1.065E-04 3.695 +7 -2.6159109447E+00 5.208E-05 3.707 +8 -2.6159109452E+00 3.393E-05 3.676 +9 -2.6159109461E+00 1.957E-05 3.684 +10 -2.6159109464E+00 9.273E-06 3.682 +11 -2.6159109475E+00 4.092E-06 3.621 +12 -2.6159109490E+00 2.191E-06 3.442 +13 -2.6159109495E+00 1.052E-06 3.450 +14 -2.6159109499E+00 3.820E-06 3.507 +15 -2.6159109502E+00 5.745E-07 3.493 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6159109502E+00 (Ha/atom) +Total free energy : -5.2318219004E+01 (Ha) +Band structure energy : -9.0987577189E+00 (Ha) +Exchange correlation energy : -2.0468535799E+01 (Ha) +Self and correction energy : -7.6945328252E+01 (Ha) +-Entropy*kb*T : -1.4325213796E-01 (Ha) +Fermi level : -2.8477339925E-02 (Ha) +RMS force : 1.1010288550E-02 (Ha/Bohr) +Maximum force : 1.4401305480E-02 (Ha/Bohr) +Time for force calculation : 0.083 (sec) +Pressure : -5.4175342909E+00 (GPa) +Maximum stress : 5.8128008839E+00 (GPa) +Time for stress calculation : 0.197 (sec) +MD step time : 61.560 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8919467398578 18.8912440561095 18.8905908355447 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149936 (Bohr) +Mesh spacing in y-direction : 0.149931 (Bohr) +Mesh spacing in z direction : 0.149925 (Bohr) +=================================================================== + Self Consistent Field (SCF#6) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6158982594E+00 3.478E-03 3.815 +2 -2.6160110490E+00 1.078E-03 3.640 +3 -2.6160124247E+00 5.547E-03 3.766 +4 -2.6160118607E+00 1.480E-03 3.697 +5 -2.6160119127E+00 2.022E-03 3.733 +6 -2.6160118374E+00 1.268E-04 3.715 +7 -2.6160118336E+00 5.207E-05 3.697 +8 -2.6160118335E+00 3.622E-05 3.669 +9 -2.6160118348E+00 2.318E-05 3.612 +10 -2.6160118350E+00 9.415E-06 3.569 +11 -2.6160118358E+00 4.934E-06 3.497 +12 -2.6160118372E+00 2.460E-06 3.608 +13 -2.6160118385E+00 5.522E-06 3.545 +14 -2.6160118377E+00 1.684E-06 3.564 +15 -2.6160118379E+00 4.134E-07 3.571 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6160118379E+00 (Ha/atom) +Total free energy : -5.2320236757E+01 (Ha) +Band structure energy : -9.0996651417E+00 (Ha) +Exchange correlation energy : -2.0471994000E+01 (Ha) +Self and correction energy : -7.6945328072E+01 (Ha) +-Entropy*kb*T : -1.4286742226E-01 (Ha) +Fermi level : -2.8526739372E-02 (Ha) +RMS force : 1.1206344424E-02 (Ha/Bohr) +Maximum force : 1.4747961077E-02 (Ha/Bohr) +Time for force calculation : 0.083 (sec) +Pressure : -5.4129992848E+00 (GPa) +Maximum stress : 5.8166069018E+00 (GPa) +Time for stress calculation : 0.198 (sec) +MD step time : 55.975 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8898019287258 18.888809755515 18.8878906276957 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149919 (Bohr) +Mesh spacing in y-direction : 0.149911 (Bohr) +Mesh spacing in z direction : 0.149904 (Bohr) +=================================================================== + Self Consistent Field (SCF#7) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6160197107E+00 3.473E-03 3.852 +2 -2.6161337943E+00 1.008E-03 3.761 +3 -2.6161350108E+00 4.569E-03 3.784 +4 -2.6161346218E+00 1.362E-03 3.732 +5 -2.6161347006E+00 2.300E-03 3.709 +6 -2.6161346042E+00 1.434E-04 3.745 +7 -2.6161346010E+00 5.802E-05 3.722 +8 -2.6161346007E+00 4.070E-05 3.582 +9 -2.6161346025E+00 2.676E-05 3.688 +10 -2.6161346028E+00 1.023E-05 3.681 +11 -2.6161346033E+00 5.285E-06 3.651 +12 -2.6161346047E+00 2.286E-06 3.421 +13 -2.6161346058E+00 3.904E-06 3.523 +14 -2.6161346060E+00 1.697E-06 3.552 +15 -2.6161346058E+00 4.179E-07 3.498 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6161346058E+00 (Ha/atom) +Total free energy : -5.2322692116E+01 (Ha) +Band structure energy : -9.1006469747E+00 (Ha) +Exchange correlation energy : -2.0476200777E+01 (Ha) +Self and correction energy : -7.6945327764E+01 (Ha) +-Entropy*kb*T : -1.4240901245E-01 (Ha) +Fermi level : -2.8581862462E-02 (Ha) +RMS force : 1.1426498999E-02 (Ha/Bohr) +Maximum force : 1.5109722204E-02 (Ha/Bohr) +Time for force calculation : 0.083 (sec) +Pressure : -5.4075539300E+00 (GPa) +Maximum stress : 5.8205449587E+00 (GPa) +Time for stress calculation : 0.197 (sec) +MD step time : 56.184 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8872833433642 18.885948409135 18.8847152449234 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149899 (Bohr) +Mesh spacing in y-direction : 0.149888 (Bohr) +Mesh spacing in z direction : 0.149879 (Bohr) +=================================================================== + Self Consistent Field (SCF#8) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6161651024E+00 3.471E-03 3.854 +2 -2.6162789162E+00 1.603E-03 3.845 +3 -2.6162817429E+00 1.069E-02 3.950 +4 -2.6162797559E+00 1.581E-03 3.730 +5 -2.6162797666E+00 1.551E-03 3.710 +6 -2.6162797214E+00 1.255E-04 3.628 +7 -2.6162797179E+00 4.991E-05 3.679 +8 -2.6162797180E+00 3.466E-05 3.597 +9 -2.6162797187E+00 2.115E-05 3.583 +10 -2.6162797189E+00 9.428E-06 3.556 +11 -2.6162797200E+00 4.481E-06 3.663 +12 -2.6162797213E+00 4.901E-06 3.530 +13 -2.6162797204E+00 6.365E-06 3.489 +14 -2.6162797218E+00 8.918E-07 3.548 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6162797218E+00 (Ha/atom) +Total free energy : -5.2325594437E+01 (Ha) +Band structure energy : -9.1016955612E+00 (Ha) +Exchange correlation energy : -2.0481161769E+01 (Ha) +Self and correction energy : -7.6945327718E+01 (Ha) +-Entropy*kb*T : -1.4187666526E-01 (Ha) +Fermi level : -2.8641846224E-02 (Ha) +RMS force : 1.1663692461E-02 (Ha/Bohr) +Maximum force : 1.5551309461E-02 (Ha/Bohr) +Time for force calculation : 0.083 (sec) +Pressure : -5.4012136322E+00 (GPa) +Maximum stress : 5.8246676088E+00 (GPa) +Time for stress calculation : 0.197 (sec) +MD step time : 52.633 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8843853044282 18.8826527812639 18.8810557454368 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149876 (Bohr) +Mesh spacing in y-direction : 0.149862 (Bohr) +Mesh spacing in z direction : 0.14985 (Bohr) +=================================================================== + Self Consistent Field (SCF#9) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6163314516E+00 3.483E-03 3.799 +2 -2.6164457728E+00 2.346E-03 3.830 +3 -2.6164495234E+00 1.264E-02 3.782 +4 -2.6164466929E+00 2.931E-03 3.645 +5 -2.6164465481E+00 1.009E-03 3.719 +6 -2.6164465359E+00 1.161E-04 3.723 +7 -2.6164465340E+00 5.643E-05 3.615 +8 -2.6164465338E+00 3.673E-05 3.681 +9 -2.6164465354E+00 2.150E-05 3.669 +10 -2.6164465357E+00 9.313E-06 3.687 +11 -2.6164465366E+00 4.326E-06 3.656 +12 -2.6164465373E+00 2.127E-06 3.545 +13 -2.6164465375E+00 9.383E-07 3.540 +Total number of SCF: 13 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6164465375E+00 (Ha/atom) +Total free energy : -5.2328930751E+01 (Ha) +Band structure energy : -9.1027952190E+00 (Ha) +Exchange correlation energy : -2.0486878458E+01 (Ha) +Self and correction energy : -7.6945327983E+01 (Ha) +-Entropy*kb*T : -1.4127051177E-01 (Ha) +Fermi level : -2.8705406048E-02 (Ha) +RMS force : 1.1912643544E-02 (Ha/Bohr) +Maximum force : 1.6297493781E-02 (Ha/Bohr) +Time for force calculation : 0.083 (sec) +Pressure : -5.3939403842E+00 (GPa) +Maximum stress : 5.8289523539E+00 (GPa) +Time for stress calculation : 0.197 (sec) +MD step time : 49.165 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8811016120712 18.8789150400976 18.8769022804101 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.14985 (Bohr) +Mesh spacing in y-direction : 0.149833 (Bohr) +Mesh spacing in z direction : 0.149817 (Bohr) +=================================================================== + Self Consistent Field (SCF#10) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6165193279E+00 3.497E-03 3.796 +2 -2.6166336278E+00 2.800E-03 3.650 +3 -2.6166376882E+00 1.335E-02 3.802 +4 -2.6166345980E+00 3.441E-03 3.736 +5 -2.6166343800E+00 9.017E-04 3.612 +6 -2.6166343736E+00 1.167E-04 3.716 +7 -2.6166343723E+00 5.702E-05 3.664 +8 -2.6166343723E+00 3.629E-05 3.697 +9 -2.6166343739E+00 2.034E-05 3.675 +10 -2.6166343741E+00 9.127E-06 3.683 +11 -2.6166343747E+00 4.355E-06 3.546 +12 -2.6166343756E+00 2.127E-06 9.028 +13 -2.6166343754E+00 8.622E-07 3.511 +Total number of SCF: 13 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6166343754E+00 (Ha/atom) +Total free energy : -5.2332687507E+01 (Ha) +Band structure energy : -9.1039714249E+00 (Ha) +Exchange correlation energy : -2.0493341844E+01 (Ha) +Self and correction energy : -7.6945328526E+01 (Ha) +-Entropy*kb*T : -1.4059188699E-01 (Ha) +Fermi level : -2.8772162153E-02 (Ha) +RMS force : 1.2169236381E-02 (Ha/Bohr) +Maximum force : 1.7092549188E-02 (Ha/Bohr) +Time for force calculation : 0.083 (sec) +Pressure : -5.3857387452E+00 (GPa) +Maximum stress : 5.8334258597E+00 (GPa) +Time for stress calculation : 0.197 (sec) +MD step time : 54.408 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8774235958374 18.8747245408583 18.8722416376902 +CHEB_DEGREE: 42 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.149821 (Bohr) +Mesh spacing in y-direction : 0.149799 (Bohr) +Mesh spacing in z direction : 0.14978 (Bohr) +=================================================================== + Self Consistent Field (SCF#11) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6167277976E+00 3.486E-03 3.813 +2 -2.6168420700E+00 1.174E-03 3.766 +3 -2.6168437383E+00 6.593E-03 3.710 +4 -2.6168430015E+00 1.240E-03 3.724 +5 -2.6168430821E+00 2.063E-03 3.723 +6 -2.6168429918E+00 1.811E-04 3.729 +7 -2.6168429881E+00 5.562E-05 3.722 +8 -2.6168429880E+00 3.905E-05 3.704 +9 -2.6168429899E+00 2.647E-05 3.663 +10 -2.6168429901E+00 1.131E-05 3.523 +11 -2.6168429903E+00 4.414E-06 3.634 +12 -2.6168429917E+00 3.153E-06 3.556 +13 -2.6168429926E+00 7.864E-06 3.551 +14 -2.6168429925E+00 1.346E-06 3.587 +15 -2.6168429922E+00 7.106E-07 3.481 +Total number of SCF: 15 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6168429922E+00 (Ha/atom) +Total free energy : -5.2336859843E+01 (Ha) +Band structure energy : -9.1052368287E+00 (Ha) +Exchange correlation energy : -2.0500548687E+01 (Ha) +Self and correction energy : -7.6945329479E+01 (Ha) +-Entropy*kb*T : -1.3984038083E-01 (Ha) +Fermi level : -2.8841379049E-02 (Ha) +RMS force : 1.2430326801E-02 (Ha/Bohr) +Maximum force : 1.7936522663E-02 (Ha/Bohr) +Time for force calculation : 0.084 (sec) +Pressure : -5.3766379493E+00 (GPa) +Maximum stress : 5.8381481897E+00 (GPa) +Time for stress calculation : 0.197 (sec) +*************************************************************************** + Timing info +*************************************************************************** +Total walltime : 686.645 sec +___________________________________________________________________________ + +*************************************************************************** +* Material Physics & Mechanics Group, Georgia Tech * +* PI: Phanish Suryanarayana * +* List of contributors: See the documentation * +* Citation: See README.md or the documentation for details * +* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * +* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * +*************************************************************************** + diff --git a/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.inpt b/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.inpt new file mode 100644 index 00000000..b8324e93 --- /dev/null +++ b/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.inpt @@ -0,0 +1,45 @@ +# nprocs: 48 +LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 +LATVEC: +1 0.0 0.0 +0.0 1.0 0.0 +0.0 0.0 1.0 +MESH_SPACING: 0.25 +BC: P P P +KPOINT_GRID: 1 1 1 +EXCHANGE_CORRELATION: GGA_PBE +TOL_SCF: 1e-6 +# TOL_POISSON: 1e-7 +# TOL_PSEUDOCHARGE: 1e-5 +MIXING_PARAMETER: 1.0 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +PRECOND_KERKER_THRESH: 0 + +# MD +MD_FLAG: 1 # 1 = MD, 0 = no MD (default) +ION_TEMP: 2400 # kelvin +# ION_TEMP_END: 1120 +MD_METHOD: NPT_NP # NVE, NVT_NH (Nose-Hoover), NVK_G (Gaussian) +#QMASS: 1600 # mass for NH thermostat +MD_TIMESTEP: 1 # fs +MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whichever comes first +#TWTIME: 1400 +RESTART_FLAG: 0 # 1 = restart MD from .restart file if present, 0 = start new +#ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) +EXTERNAL_PRESSURE: 0.1 GPa +#EXTERNAL_STRESS: 0 0 0 0 0 0 +NPT_NP_QMASS: 2000 +NPT_NP_BMASS: 0.5 +NPT_NP_ANGLES: 1 +#NPT_SCALE_CONSTRAINTS: 12 + +NSTATES: 80 + +# outputs +# CALC_PRES: 1 +CALC_STRESS: 1 # whether this selection changes the result of NPT? +PRINT_ATOMS: 1 +# PRINT_VELS: 1 +PRINT_FORCES: 1 +PRINT_MDOUT: 1 # print MD output to .aimd file diff --git a/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.ion b/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.ion new file mode 100644 index 00000000..b6420e8f --- /dev/null +++ b/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.ion @@ -0,0 +1,41 @@ +#CELL: 15 15 15 +#LATVEC +# 1.000000000000000 0.000000000000000 0.000000000000000 +# 0.000000000000000 1.000000000000000 0.000000000000000 +# 0.100000000000000 0.100000000000000 0.900000000000000 +#PBC: True True True +# + + +ATOM_TYPE: Al # atom type followed with valence charge +N_TYPE_ATOM: 18 # number of atoms of this type +PSEUDO_POT: ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +ATOMIC_MASS: 26.9815385 +COORD_FRAC: # coordinates follows +0.0 0.0 0.0 +0.0 0.0 0.333333 +0.0 0.0 0.666666 +0.0 0.333333 0.0 +0.0 0.333333 0.333333 +0.0 0.333333 0.666666 +0.0 0.666666 0.0 +0.0 0.666666 0.333333 +0.0 0.666666 0.666666 +0.333333 0.0 0.0 +0.333333 0.0 0.333333 +0.333333 0.0 0.666666 +0.333333 0.333333 0.0 +0.333333 0.333333 0.333333 +0.333333 0.333333 0.666666 +0.333333 0.666666 0.0 +0.333333 0.666666 0.333333 +0.333333 0.666666 0.666666 + + +ATOM_TYPE: C # atom type followed with valence charge +N_TYPE_ATOM: 2 # number of atoms of this type +PSEUDO_POT: ../../../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 +ATOMIC_MASS: 12.011 +COORD_FRAC: # coordinates follows +0.666666 0.0 0.0 +0.666666 0.0 0.333333 diff --git a/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.refaimd b/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.refaimd new file mode 100644 index 00000000..db1eb361 --- /dev/null +++ b/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.refaimd @@ -0,0 +1,1168 @@ +:Description: + +:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr +:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu + where atu is the atomic unit of time, hbar/Ha +:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr +:Desc_MDTM: MD time. Unit=second +:Desc_TEL: Electronic temperature. Unit=Kelvin +:Desc_TIO: Ionic temperature. Unit=Kelvin +:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom +:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom +:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom + where N = number of particles, k = Boltzmann constant +:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom +:Desc_UEN: Internal energy. Unit=Ha/atom +:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom +:Desc_ANGLES: angles between cell lattice vectors. Format: (angle between 1 and 2, angle between 1 and 3, angle between 2 and 3). Unit = Degree +:Desc_VOLUME: Volume of the full lattice. Unit = Bohr^3 +:Desc_LATVEC_SCALE: ratio of length of cell lattice vectors over length of input lattice vectors. Unit = 1 +:Desc_LatVec: Lattice vectors, purpose: only to represent change in angles during NPT_NP ensemble (has same magnitude as initial LatVec). Unit = Bohr +:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha +:Desc_SNOSE[0]: Position variable of the thermostat +:Desc_SNOSE[1]: Velocity variable of the thermostat +:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_CONSTRESS: Constraint stress (due to restricting cell's full flexibility) in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_TOTSTRESS: Total internal stress in cartesian coordinate (also accounting stresses due to any constraint on cell flexibility). Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) +:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa +:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa +:Desc_CONPRES: Constraint pressure (pressure due to restricting cell flexibility). Unit=GPa +:Desc_TOTPRES: Total internal pressure (also accounting pressure due to any constraint on cell flexibility). Unit=GPa +:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa + where N = number of particles, k = Boltzmann constant, V = volume +:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu +:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr + + + + +:MDSTEP: 1 +:MDTM: 33.81 +:TWIST: 0 +:TEL: 2400 +:TIO: 2400.33435869236 +:TEN: -2.6048803826E+00 +:KEN: 1.0832004410E-02 +:KENIG: 1.1402109905E-02 +:FEN: -2.6157123870E+00 +:UEN: -2.6085116859E+00 +:TSEN: -7.2007010776E-03 +:NPT_NP_HAMIL: 3.9147611297E-05 +:SNOSE[0]: 1.0000000000E+00 +:SNOSE[1]: 0.0000000000E+00 +:R: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 6.2990803296E+00 + 0.0000000000E+00 0.0000000000E+00 1.2598160659E+01 + 0.0000000000E+00 6.2990803296E+00 0.0000000000E+00 + 0.0000000000E+00 6.2990803296E+00 6.2990803296E+00 + 0.0000000000E+00 6.2990803296E+00 1.2598160659E+01 + 0.0000000000E+00 1.2598160659E+01 0.0000000000E+00 + 0.0000000000E+00 1.2598160659E+01 6.2990803296E+00 + 0.0000000000E+00 1.2598160659E+01 1.2598160659E+01 + 6.2990803296E+00 0.0000000000E+00 0.0000000000E+00 + 6.2990803296E+00 0.0000000000E+00 6.2990803296E+00 + 6.2990803296E+00 0.0000000000E+00 1.2598160659E+01 + 6.2990803296E+00 6.2990803296E+00 0.0000000000E+00 + 6.2990803296E+00 6.2990803296E+00 6.2990803296E+00 + 6.2990803296E+00 6.2990803296E+00 1.2598160659E+01 + 6.2990803296E+00 1.2598160659E+01 0.0000000000E+00 + 6.2990803296E+00 1.2598160659E+01 6.2990803296E+00 + 6.2990803296E+00 1.2598160659E+01 1.2598160659E+01 + 1.2598160659E+01 0.0000000000E+00 0.0000000000E+00 + 1.2598160659E+01 0.0000000000E+00 6.2990803296E+00 +:V: + -6.7710516109E-06 6.8757510825E-04 4.3936034575E-04 + 3.7347472549E-05 -1.5727035835E-04 5.1719495082E-04 + 6.4986537421E-04 -4.5410617444E-04 -3.0784834225E-04 + -3.2394292752E-04 -1.3629798900E-04 -4.4900352071E-04 + 2.9184758378E-04 4.0511650521E-04 -3.3972581643E-05 + -1.6699277886E-04 3.6969211444E-04 -5.9863718038E-05 + -7.8895390013E-04 -5.9299432692E-04 2.6594936923E-04 + 4.8089643711E-05 1.3106984986E-04 3.9308987951E-04 + 4.6023630212E-04 -4.7428024753E-04 1.4680482193E-04 + -4.4619399353E-04 -2.7196367835E-05 -6.1811110305E-04 + 2.1182560098E-05 1.9314804078E-05 -3.0795927370E-04 + 9.2716454044E-05 -4.7512762063E-04 4.3478005477E-04 + 5.4429854058E-04 -4.6901364919E-05 3.8053261087E-04 + 7.8083445950E-04 3.4892961220E-04 -5.1049137060E-05 + -7.0230024838E-04 5.7124825455E-04 -2.9842626682E-04 + 5.5675786118E-05 -8.3790414993E-04 -5.9249441287E-05 + -3.2642657252E-04 5.9659856045E-04 -2.8121297060E-05 + -1.4748597462E-04 9.7058121216E-06 -4.3002564883E-04 + 1.9870075470E-04 1.8287980689E-04 2.9481010274E-04 + -3.6274817079E-04 -4.1742889245E-05 -1.4673108487E-04 +:F: + -3.2347216855E-03 1.4481790540E-07 3.2351661950E-04 + -3.2063135076E-03 1.3898787963E-07 -3.2971708039E-04 + 1.1731164796E-02 1.3995495613E-07 3.4327772902E-06 + 1.2517215501E-02 -2.4488069186E-04 1.2723590547E-04 + 1.2519615772E-02 -2.4351024796E-04 -1.2568069032E-04 + 1.3274635348E-02 -5.4425631608E-05 -1.7576373296E-06 + 1.2517197377E-02 2.4474097758E-04 1.2723543004E-04 + 1.2519576590E-02 2.4337660087E-04 -1.2566948069E-04 + 1.3274609149E-02 5.4279974201E-05 -1.7676399817E-06 + 3.2382852921E-03 1.4866750652E-07 3.2357121515E-04 + 3.2088680716E-03 1.3936567492E-07 -3.2613188578E-04 + -1.1732221517E-02 1.3952836546E-07 2.3719274610E-06 + -1.2517458767E-02 -2.4411765567E-04 1.2708134159E-04 + -1.2518301654E-02 -2.4484026810E-04 -1.2711667172E-04 + -1.3273333171E-02 -5.5827097645E-05 -3.0508209228E-07 + -1.2517446637E-02 2.4397174952E-04 1.2708573871E-04 + -1.2518273150E-02 2.4470536182E-04 -1.2710730876E-04 + -1.3273310498E-02 5.5678942845E-05 -3.1423737134E-07 + -5.4908577410E-06 3.9478144203E-08 1.1878563395E-02 + -4.2964508391E-06 -4.2814413868E-08 -1.1874526636E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7483330373E+03 +:LATVEC_SCALE: + 1.8897259886E+01 1.8897259886E+01 1.8897259886E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 1.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 1.0000000000E+00 +:STRIO: + 7.0617039596E-01 -7.6080172092E-02 1.3808687578E-01 + -7.6080172092E-02 7.2214947933E-01 -2.9245140382E-02 + 1.3808687578E-01 -2.9245140382E-02 4.6067149486E-01 +:STRESS: + 4.9561080977E+00 -2.1398714969E-07 4.1916282412E-05 + -2.1398714969E-07 5.5315581576E+00 -4.4666813957E-07 + 4.1916282412E-05 -4.4666813957E-07 5.8022454141E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2499377017E+00 -7.6079958105E-02 1.3804495950E-01 + -7.6079958105E-02 -4.8094086783E+00 -2.9244693714E-02 + 1.3804495950E-01 -2.9244693714E-02 -5.3415739192E+00 +:PRESIO: 6.2966379005E-01 +:PRES: -5.4299705565E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.8003067664E+00 +:PRESIG: 6.6280398953E-01 +:MIND: +Al - Al: 6.2990803296E+00 +C - C: 6.2990803296E+00 +Al - C: 6.2990803296E+00 + + +:MDSTEP: 2 +:MDTM: 25.89 +:TWIST: 0 +:TEL: 2400 +:TIO: 2403.18956278708 +:TEN: -2.6048867932E+00 +:KEN: 1.0844889108E-02 +:KENIG: 1.1415672745E-02 +:FEN: -2.6157316823E+00 +:UEN: -2.6085363513E+00 +:TSEN: -7.1953310156E-03 +:NPT_NP_HAMIL: -9.5242020786E-06 +:SNOSE[0]: 1.0000212597E+00 +:SNOSE[1]: 4.8414875003E-06 +:R: + 1.8896569962E+01 2.8424394379E-02 1.8168762340E-02 + 1.4833825683E-03 1.8890357405E+01 6.3203078859E+00 + 2.7071947811E-02 1.8878084618E+01 1.2585139206E+01 + 1.8883750010E+01 6.2933036466E+00 1.8878257696E+01 + 1.2285889312E-02 6.3156889456E+00 6.2975261840E+00 + 1.8890244034E+01 6.3142261988E+00 1.2595390791E+01 + 1.8864499847E+01 1.2573384270E+01 1.0996548358E-02 + 2.2047992243E-03 1.2603315516E+01 6.3151809317E+00 + 1.9263615967E-02 1.2578285438E+01 1.2603934461E+01 + 6.2805829746E+00 1.8895731512E+01 1.8871270206E+01 + 6.2999013041E+00 7.9689494692E-04 6.2861961009E+00 + 6.3025940989E+00 1.8877215582E+01 1.2615839420E+01 + 6.3212421972E+00 6.2970040706E+00 1.5733412950E-02 + 6.3310280691E+00 6.3133661532E+00 6.2968202148E+00 + 6.2697093928E+00 6.3225585199E+00 1.2585528649E+01 + 6.3010607861E+00 1.2563254916E+01 1.8894370114E+01 + 6.2852495903E+00 1.2622560529E+01 6.2977680511E+00 + 6.2926413871E+00 1.2598293481E+01 1.2580088335E+01 + 1.2606138902E+01 7.5602606006E-03 1.2651046168E-02 + 1.2582923653E+01 1.8895133321E+01 6.2924034858E+00 +:V: + -9.5062069917E-06 6.8789354852E-04 4.3970425232E-04 + 3.4774706051E-05 -1.5741673940E-04 5.1705461609E-04 + 6.5972945904E-04 -4.5424668045E-04 -3.0803315429E-04 + -3.1351143216E-04 -1.3659849179E-04 -4.4896792669E-04 + 3.0232054470E-04 4.0502414981E-04 -3.3983548629E-05 + -1.5574284886E-04 3.6991360712E-04 -5.9835611757E-05 + -7.7855781906E-04 -5.9303036437E-04 2.6605906177E-04 + 5.8698676270E-05 1.3131526142E-04 3.9300327450E-04 + 4.7146104819E-04 -4.7433061253E-04 1.4675687338E-04 + -4.4380237467E-04 -2.7035157918E-05 -6.1806965032E-04 + 2.4068671886E-05 1.9167125204E-05 -3.0829528667E-04 + 8.2857255327E-05 -4.7534637212E-04 4.3504591402E-04 + 5.3386189301E-04 -4.6997997085E-05 3.8076790289E-04 + 7.7037941821E-04 3.4867457325E-04 -5.1149164541E-05 + -7.1354552026E-04 5.7144802721E-04 -2.9860866361E-04 + 4.5250896124E-05 -8.3794346813E-04 -5.9082191659E-05 + -3.3702860228E-04 5.9696156465E-04 -2.8158772580E-05 + -1.5872331511E-04 9.7189826173E-06 -4.3013973406E-04 + 1.9930623941E-04 1.8282341537E-04 3.1753861338E-04 + -3.6325867732E-04 -4.1684104000E-05 -1.6942924152E-04 +:F: + -3.2734227848E-03 7.5778150679E-04 4.9208646484E-04 + -2.9151725609E-03 -3.4854556699E-04 -6.6636285035E-06 + 1.1743630947E-02 -3.3562195297E-04 -4.3947121203E-04 + 1.2301815614E-02 -4.6968779869E-04 -4.1051697494E-05 + 1.2401795888E-02 2.3417710181E-05 1.0035819711E-04 + 1.3492748224E-02 5.8181470909E-04 6.8264589108E-05 + 1.2214761662E-02 -3.2944833686E-04 1.3053987468E-04 + 1.2724136132E-02 3.4051839521E-04 -8.2350933541E-05 + 1.3436636595E-02 -1.7498984192E-04 -1.1147647529E-04 + 2.4497063124E-03 3.8412311330E-04 -2.2299896250E-04 + 3.6585526637E-03 -3.5155931856E-04 -4.7174790827E-04 + -1.1726466493E-02 -5.2092345304E-04 6.2851547008E-04 + -1.2312501735E-02 1.3334372314E-05 4.3237208841E-04 + -1.2353997788E-02 -3.6310823377E-04 -1.0864402227E-04 + -1.3488213091E-02 5.3244793733E-04 -4.3450244174E-04 + -1.2287486530E-02 -3.3785980156E-04 2.7182118308E-04 + -1.2710456756E-02 6.1973407427E-04 3.6786753497E-05 + -1.3466015217E-02 -2.4099244465E-05 -2.6936861178E-04 + 6.4736351395E-04 -5.9883339894E-05 1.2195329729E-02 + -5.3741459608E-04 6.2555070242E-05 -1.2167798457E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7479060373E+03 +:LATVEC_SCALE: + 1.8896906075E+01 1.8896860560E+01 1.8896817276E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -6.5496499554E-07 1.0000000000E+00 0.0000000000E+00 + 1.1884155035E-06 -2.5176429008E-07 1.0000000000E+00 +:STRIO: + 7.0587874148E-01 -7.8721781245E-02 1.3853820310E-01 + -7.8721781245E-02 7.2255514116E-01 -2.8782167432E-02 + 1.3853820310E-01 -2.8782167432E-02 4.6292412324E-01 +:STRESS: + 4.9486054051E+00 -1.5747634021E-03 1.6137337251E-03 + -1.5747634021E-03 5.5343761165E+00 5.8815711744E-04 + 1.6137337251E-03 5.8815711744E-04 5.8059466318E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2427266636E+00 -7.7147017842E-02 1.3692446938E-01 + -7.7147017842E-02 -4.8118209753E+00 -2.9370324549E-02 + 1.3692446938E-01 -2.9370324549E-02 -5.3430225086E+00 +:PRESIO: 6.3045266862E-01 +:PRES: -5.4296427178E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7991900492E+00 +:PRESIG: 6.6363438803E-01 +:MIND: +Al - Al: 6.2554969145E+00 +C - C: 6.2798069764E+00 +Al - C: 6.2830259266E+00 + + +:MDSTEP: 3 +:MDTM: 24.66 +:TWIST: 0 +:TEL: 2400 +:TIO: 2407.58035390553 +:TEN: -2.6049067268E+00 +:KEN: 1.0864703459E-02 +:KENIG: 1.1436529957E-02 +:FEN: -2.6157714303E+00 +:UEN: -2.6085847481E+00 +:TSEN: -7.1866821683E-03 +:NPT_NP_HAMIL: -4.1443199241E-05 +:SNOSE[0]: 1.0005422108E+00 +:SNOSE[1]: 2.3931527222E-05 +:R: + 1.8895412967E+01 5.6866194285E-02 3.6348851521E-02 + 2.8599964951E-03 1.8883043445E+01 6.3413807342E+00 + 5.4545800003E-02 1.8858500611E+01 1.2571811136E+01 + 1.8870336129E+01 6.2873743716E+00 1.8858816956E+01 + 2.5002019018E-02 6.3321582788E+00 6.2958282824E+00 + 1.8883356128E+01 6.3292510353E+00 1.2592328735E+01 + 1.8831812371E+01 1.2548337553E+01 2.1994168494E-02 + 4.8500425796E-03 1.2608212366E+01 6.3311258282E+00 + 3.8994613120E-02 1.2558140568E+01 1.2609407076E+01 + 6.2620682109E+00 1.8893812261E+01 1.8844837883E+01 + 6.3007386462E+00 1.5797435840E-03 6.2731518531E+00 + 6.3055839686E+00 1.8856756337E+01 1.2633238933E+01 + 6.3428475238E+00 6.2947956198E+00 3.1476817925E-02 + 6.3624221452E+00 6.3275000077E+00 6.2944092840E+00 + 6.2397716784E+00 6.3459113450E+00 1.2572590149E+01 + 6.3025099045E+00 1.2528076975E+01 1.8891047513E+01 + 6.2708627168E+00 1.2646706064E+01 6.2963097643E+00 + 6.2856252056E+00 1.2598155629E+01 1.2561716953E+01 + 1.2613929518E+01 1.5113474959E-02 2.6249742656E-02 + 1.2567408537E+01 1.8892610780E+01 6.2846315249E+00 +:V: + -1.2270004184E-05 6.8852391585E-04 4.3998196718E-04 + 3.2429658402E-05 -1.5777952196E-04 5.1693915303E-04 + 6.6928214510E-04 -4.5445532730E-04 -3.0844326311E-04 + -3.0311824041E-04 -1.3702097859E-04 -4.4885835666E-04 + 3.1254842570E-04 4.0496122292E-04 -3.3789442098E-05 + -1.4423961326E-04 3.7049131919E-04 -5.9718327750E-05 + -7.6804560236E-04 -5.9327311812E-04 2.6604559879E-04 + 6.9449030785E-05 1.3157879001E-04 3.9276507809E-04 + 4.8258973159E-04 -4.7434432294E-04 1.4654462199E-04 + -4.4185596751E-04 -2.6536298651E-05 -6.1819352165E-04 + 2.7322154960E-05 1.8717096818E-05 -3.0860738010E-04 + 7.2966885933E-05 -4.7577666950E-04 4.3562821747E-04 + 5.2334753159E-04 -4.6855534513E-05 3.8107886274E-04 + 7.5969542863E-04 3.4815327045E-04 -5.1213371991E-05 + -7.2462402598E-04 5.7186967555E-04 -2.9901183388E-04 + 3.4999334851E-05 -8.3807354855E-04 -5.8765192631E-05 + -3.4762466150E-04 5.9735075098E-04 -2.8046002115E-05 + -1.7004238137E-04 9.6644952386E-06 -4.3027292618E-04 + 2.0103985264E-04 1.8256959921E-04 3.4074633856E-04 + -3.6460002724E-04 -4.1484787470E-05 -1.9262728685E-04 +:F: + -3.3153365252E-03 1.5255677084E-03 6.6379517163E-04 + -2.6261131195E-03 -6.9413033771E-04 3.1524442241E-04 + 1.1750546498E-02 -6.8016095247E-04 -8.7955583528E-04 + 1.2073443425E-02 -6.9033698592E-04 -2.0600520338E-04 + 1.2288298417E-02 2.8694451194E-04 3.2448298417E-04 + 1.3705766324E-02 1.2146358902E-03 1.4208623580E-04 + 1.1908919786E-02 -9.2095277652E-04 1.3380616387E-04 + 1.2929164854E-02 4.3596826619E-04 -4.1172967128E-05 + 1.3591839891E-02 -3.9915293930E-04 -2.2489806581E-04 + 1.6724877814E-03 7.7367363029E-04 -7.7113921702E-04 + 4.1123083426E-03 -6.9767947574E-04 -6.1853745385E-04 + -1.1717310808E-02 -1.0445254483E-03 1.2488218270E-03 + -1.2097700498E-02 2.7049297817E-04 7.4006039442E-04 + -1.2187875699E-02 -4.8296532855E-04 -9.7959946074E-05 + -1.3699261821E-02 1.1238336009E-03 -8.6641321795E-04 + -1.2059233359E-02 -9.2578974548E-04 4.1720394909E-04 + -1.2895748969E-02 9.8720808113E-04 1.9716717883E-04 + -1.3655866968E-02 -9.3981672442E-05 -5.3356832536E-04 + 1.2912394049E-03 -1.1662872384E-04 1.2552203273E-02 + -1.0695669573E-03 1.2797971909E-04 -1.2495621368E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7470518922E+03 +:LATVEC_SCALE: + 1.8896198797E+01 1.8896061435E+01 1.8895931628E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.9746432396E-06 1.0000000000E+00 0.0000000000E+00 + 3.5566101471E-06 -7.5658744299E-07 9.9999999999E-01 +:STRIO: + 7.0618961717E-01 -8.1420596190E-02 1.3919822142E-01 + -8.1420596190E-02 7.2331968615E-01 -2.8343227416E-02 + 1.3919822142E-01 -2.8343227416E-02 4.6554421704E-01 +:STRESS: + 4.9397253167E+00 -3.2270128206E-03 2.6675041497E-03 + -3.2270128206E-03 5.5351538027E+00 1.6609075578E-03 + 2.6675041497E-03 1.6609075578E-03 5.8097443730E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2335356996E+00 -7.8193583369E-02 1.3653071727E-01 + -7.8193583369E-02 -4.8118341165E+00 -3.0004134973E-02 + 1.3653071727E-01 -3.0004134973E-02 -5.3442001559E+00 +:PRESIO: 6.3168450679E-01 +:PRES: -5.4282078308E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7965233240E+00 +:PRESIG: 6.6493105978E-01 +:MIND: +Al - Al: 6.2118619006E+00 +C - C: 6.2585965125E+00 +Al - C: 6.2666824505E+00 + + +:MDSTEP: 4 +:MDTM: 15.52 +:TWIST: 0 +:TEL: 2400 +:TIO: 2410.15232144263 +:TEN: -2.6049547010E+00 +:KEN: 1.0876309994E-02 +:KENIG: 1.1448747362E-02 +:FEN: -2.6158310110E+00 +:UEN: -2.6086563367E+00 +:TSEN: -7.1746743207E-03 +:NPT_NP_HAMIL: -4.1783517186E-05 +:SNOSE[0]: 1.0022656327E+00 +:SNOSE[1]: 5.6249418988E-05 +:R: + 1.8893787333E+01 8.5327266119E-02 5.4530355012E-02 + 4.1386129587E-03 1.8875310085E+01 6.3622907939E+00 + 8.2397380862E-02 1.8838510655E+01 1.2558171054E+01 + 1.8857020285E+01 6.2812891426E+00 1.8838946331E+01 + 3.8132937192E-02 6.3484823605E+00 6.2939950102E+00 + 1.8876607822E+01 6.3441628756E+00 1.2588978009E+01 + 1.8799213491E+01 1.2523020259E+01 3.2983402879E-02 + 7.9400418659E-03 1.2612848703E+01 6.3469016711E+00 + 5.9180755707E-02 1.2537734232E+01 1.2614568040E+01 + 6.2435243975E+00 1.8891514940E+01 1.8817964396E+01 + 6.3016068475E+00 2.3358234840E-03 6.2599530246E+00 + 6.3080474923E+00 1.8835879456E+01 1.2650363797E+01 + 6.3638849569E+00 6.2924650844E+00 4.7227118029E-02 + 6.3932409787E+00 6.3414646720E+00 6.2918491196E+00 + 6.2092857540E+00 6.3691381449E+00 1.2559339786E+01 + 6.3034342730E+00 1.2492635430E+01 1.8887297424E+01 + 6.2559255754E+00 1.2670587439E+01 6.2947114690E+00 + 6.2780311359E+00 1.2597743218E+01 1.2543051667E+01 + 1.2621575124E+01 2.2648645412E-02 4.0811172558E-02 + 1.2551586253E+01 1.8889697263E+01 6.2757456889E+00 +:V: + -1.5053491623E-05 6.8898916580E-04 4.3988782884E-04 + 3.0291600141E-05 -1.5824438482E-04 5.1648386068E-04 + 6.7803750774E-04 -4.5442078021E-04 -3.0885804822E-04 + -2.9257554363E-04 -1.3746493714E-04 -4.4835798859E-04 + 3.2230301820E-04 4.0464072607E-04 -3.3368899585E-05 + -1.3240088874E-04 3.7116083264E-04 -5.9467162374E-05 + -7.5689605165E-04 -5.9331937450E-04 2.6572244726E-04 + 8.0278331708E-05 1.3176664408E-04 3.9209959959E-04 + 4.9326380476E-04 -4.7398441443E-04 1.4606252043E-04 + -4.4003717347E-04 -2.5678251323E-05 -6.1804931035E-04 + 3.0921848397E-05 1.7957395268E-05 -3.0867913281E-04 + 6.3009836629E-05 -4.7608622840E-04 4.3621376965E-04 + 5.1241050355E-04 -4.6442825138E-05 3.8119962039E-04 + 7.4826587709E-04 3.4712201686E-04 -5.1212044845E-05 + -7.3501077054E-04 5.7211352316E-04 -2.9942326201E-04 + 2.4908524927E-05 -8.3771061915E-04 -5.8257011660E-05 + -3.5795161846E-04 5.9734043486E-04 -2.7766983180E-05 + -1.8130637798E-04 9.5446557334E-06 -4.3011914415E-04 + 2.0374017965E-04 1.8199731536E-04 3.6424102388E-04 + -3.6651210538E-04 -4.1111001334E-05 -2.1622705426E-04 +:F: + -3.3618416347E-03 2.2972250126E-03 8.3852319187E-04 + -2.3372448004E-03 -1.0350145088E-03 6.3107503088E-04 + 1.1750780410E-02 -1.0327718786E-03 -1.3127326384E-03 + 1.1832430562E-02 -9.0569907300E-04 -3.6742844980E-04 + 1.2179542412E-02 5.4520279953E-04 5.4604743870E-04 + 1.3915473665E-02 1.8410346934E-03 2.1958805351E-04 + 1.1600434401E-02 -1.5248499481E-03 1.3616511786E-04 + 1.3134728086E-02 5.2987821019E-04 -6.6266032816E-07 + 1.3739037253E-02 -6.1663391799E-04 -3.4254506533E-04 + 9.0908595998E-04 1.1667902413E-03 -1.3165911304E-03 + 4.5678732689E-03 -1.0375101312E-03 -7.6404403795E-04 + -1.1705419139E-02 -1.5689287043E-03 1.8574535788E-03 + -1.1874815082E-02 5.2487081754E-04 1.0483852342E-03 + -1.2021233791E-02 -6.0328140506E-04 -9.4285662632E-05 + -1.3906102925E-02 1.7151985153E-03 -1.2945632280E-03 + -1.1832616383E-02 -1.5148069920E-03 5.6382975557E-04 + -1.3073834000E-02 1.3454549689E-03 3.5294157953E-04 + -1.3841714569E-02 -1.5240588201E-04 -7.9138347020E-04 + 1.9253599335E-03 -1.6990563475E-04 1.2950293329E-02 + -1.5999236267E-03 1.9615281692E-04 -1.2860065967E-02 +:ANGLES: + 90.000 90.000 90.000 +:VOLUME: 6.7457692894E+03 +:LATVEC_SCALE: + 1.8895137439E+01 1.8894860960E+01 1.8894601127E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -3.9708629633E-06 9.9999999999E-01 0.0000000000E+00 + 7.1061833959E-06 -1.5210029575E-06 9.9999999997E-01 +:STRIO: + 7.0611121738E-01 -8.4054425938E-02 1.3988027541E-01 + -8.4054425938E-02 7.2343455697E-01 -2.7891185879E-02 + 1.3988027541E-01 -2.7891185879E-02 4.6789289169E-01 +:STRESS: + 4.9294897868E+00 -4.9708329762E-03 3.1483493684E-03 + -4.9708329762E-03 5.5338691824E+00 3.2098841977E-03 + 3.1483493684E-03 3.2098841977E-03 5.8135811834E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2233785695E+00 -7.9083592961E-02 1.3673192605E-01 + -7.9083592961E-02 -4.8104346254E+00 -3.1101070077E-02 + 1.3673192605E-01 -3.1101070077E-02 -5.3456882918E+00 +:PRESIO: 6.3247955535E-01 +:PRES: -5.4256467175E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7931671622E+00 +:PRESIG: 6.6576795300E-01 +:MIND: +Al - Al: 6.1681890117E+00 +C - C: 6.2354180903E+00 +Al - C: 6.2500039306E+00 + + +:MDSTEP: 5 +:MDTM: 17.79 +:TWIST: 0 +:TEL: 2400 +:TIO: 2409.01748906681 +:TEN: -2.6050382515E+00 +:KEN: 1.0871188828E-02 +:KENIG: 1.1443356661E-02 +:FEN: -2.6159094403E+00 +:UEN: -2.6087501788E+00 +:TSEN: -7.1592615254E-03 +:NPT_NP_HAMIL: 1.0193526942E-05 +:SNOSE[0]: 1.0055927718E+00 +:SNOSE[1]: 9.0618281696E-05 +:R: + 1.8891689791E+01 1.1379400401E-01 7.2693533625E-02 + 5.3274769263E-03 1.8867150823E+01 6.3830172225E+00 + 1.1058648574E-01 1.8818125131E+01 1.2544218994E+01 + 1.8843808127E+01 6.2750470410E+00 1.8818661973E+01 + 5.1655481869E-02 6.3646451094E+00 6.2920344726E+00 + 1.8870010910E+01 6.3589602481E+00 1.2585341760E+01 + 1.8766733386E+01 1.2497443574E+01 4.3948782009E-02 + 1.1476619661E-02 1.2617217394E+01 6.3624853667E+00 + 7.9797789720E-02 1.2517083909E+01 1.2619401654E+01 + 6.2249496908E+00 1.8888850567E+01 1.8790662544E+01 + 6.3025188997E+00 3.0522496153E-03 6.2466111676E+00 + 6.3099809867E+00 1.8814590607E+01 1.2667206476E+01 + 6.3843318888E+00 6.2900227146E+00 6.2972615328E-02 + 6.4234462594E+00 6.3552343337E+00 6.2891413076E+00 + 6.1782870818E+00 6.3922244654E+00 1.2545777297E+01 + 6.3038400511E+00 1.2456956082E+01 1.8883123776E+01 + 6.2404524198E+00 1.2694179427E+01 6.2929787007E+00 + 6.2698629588E+00 1.2597050937E+01 1.2524105739E+01 + 1.2629111387E+01 3.0150975929E-02 5.6343793535E-02 + 1.2535434956E+01 1.8886396527E+01 6.2657299562E+00 +:V: + -1.7848312985E-05 6.8901792307E-04 4.3925248526E-04 + 2.8354388949E-05 -1.5874323872E-04 5.1548167343E-04 + 6.8570212534E-04 -4.5397207553E-04 -3.0914845463E-04 + -2.8180590915E-04 -1.3786872898E-04 -4.4728992296E-04 + 3.3143816918E-04 4.0390002216E-04 -3.2712825112E-05 + -1.2020776948E-04 3.7176864370E-04 -5.9056994418E-05 + -7.4484320092E-04 -5.9294591297E-04 2.6498572804E-04 + 9.1127442574E-05 1.3182575483E-04 3.9085552438E-04 + 5.0325626759E-04 -4.7306053663E-04 1.4525141109E-04 + -4.3816473072E-04 -2.4452124610E-05 -6.1739074062E-04 + 3.4846518165E-05 1.6889003449E-05 -3.0838834549E-04 + 5.2989391886E-05 -4.7608720216E-04 4.3661783157E-04 + 5.0088434868E-04 -4.5746558958E-05 3.8098100641E-04 + 7.3582746097E-04 3.4544757931E-04 -5.1131323570E-05 + -7.4438840942E-04 5.7195335113E-04 -2.9972021752E-04 + 1.4992395984E-05 -8.3652639872E-04 -5.7535498603E-05 + -3.6783690873E-04 5.9668954958E-04 -2.7316029271E-05 + -1.9241173099E-04 9.3658999610E-06 -4.2950459055E-04 + 2.0729858992E-04 1.8104425239E-04 3.8789730208E-04 + -3.6884083471E-04 -4.0542905532E-05 -2.4015303192E-04 +:F: + -3.4149273115E-03 3.0640118240E-03 1.0153387379E-03 + -2.0466779351E-03 -1.3694016735E-03 9.3774396546E-04 + 1.1741854116E-02 -1.3931562358E-03 -1.7362071288E-03 + 1.1580099958E-02 -1.1106861373E-03 -5.2485854557E-04 + 1.2076251735E-02 7.9605563571E-04 7.6423118550E-04 + 1.4123354231E-02 2.4591570625E-03 2.9986576377E-04 + 1.1291881372E-02 -2.1380574006E-03 1.3687132868E-04 + 1.3340099352E-02 6.2272695385E-04 4.0375349631E-05 + 1.3877190974E-02 -8.2621613776E-04 -4.6448339814E-04 + 1.6326083779E-04 1.5602692998E-03 -1.8531061628E-03 + 5.0232859577E-03 -1.3704487518E-03 -9.0733411341E-04 + -1.1690486482E-02 -2.0909184379E-03 2.4484733958E-03 + -1.1646384047E-02 7.7403253274E-04 1.3565137851E-03 + -1.1856272555E-02 -7.2479297657E-04 -9.8168032631E-05 + -1.4107895068E-02 2.3026722325E-03 -1.7162815694E-03 + -1.1608665005E-02 -2.0985968963E-03 7.1143248675E-04 + -1.3244055101E-02 1.6947210623E-03 5.0324840944E-04 + -1.4022482708E-02 -1.9901064154E-04 -1.0410823560E-03 + 2.5478649466E-03 -2.1923376279E-04 1.3389544529E-02 + -2.1272972687E-03 2.6687244840E-04 -1.3262117630E-02 +:ANGLES: + 90.000 89.999 90.000 +:VOLUME: 6.7440544298E+03 +:LATVEC_SCALE: + 1.8893719322E+01 1.8893255265E+01 1.8892821227E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -6.6583845801E-06 9.9999999998E-01 0.0000000000E+00 + 1.1851290590E-05 -2.5572159788E-06 9.9999999993E-01 +:STRIO: + 7.0508535331E-01 -8.6541979362E-02 1.4048054722E-01 + -8.6541979362E-02 7.2233300415E-01 -2.7408024705E-02 + 1.4048054722E-01 -2.7408024705E-02 4.6960913833E-01 +:STRESS: + 4.9180394587E+00 -6.7940491353E-03 2.9977358941E-03 + -6.7940491353E-03 5.5306014469E+00 5.2227193681E-03 + 2.9977358941E-03 5.2227193681E-03 5.8174571383E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2129541054E+00 -7.9747930227E-02 1.3748281133E-01 + -7.9747930227E-02 -4.8082684427E+00 -3.2630744073E-02 + 1.3748281133E-01 -3.2630744073E-02 -5.3478480000E+00 +:PRESIO: 6.3234249860E-01 +:PRES: -5.4220326813E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7896901827E+00 +:PRESIG: 6.6562368273E-01 +:MIND: +Al - Al: 6.1244966393E+00 +C - C: 6.2102513235E+00 +Al - C: 6.2329534072E+00 + + +:MDSTEP: 6 +:MDTM: 17.86 +:TWIST: 0 +:TEL: 2400 +:TIO: 2405.26118049841 +:TEN: -2.6051539243E+00 +:KEN: 1.0854237710E-02 +:KENIG: 1.1425513379E-02 +:FEN: -2.6160081620E+00 +:UEN: -2.6088677608E+00 +:TSEN: -7.1404012455E-03 +:NPT_NP_HAMIL: 8.5605101441E-05 +:SNOSE[0]: 1.0103139080E+00 +:SNOSE[1]: 1.1445631648E-04 +:R: + 1.8889114980E+01 1.4225019770E-01 9.0817252389E-02 + 6.4350259550E-03 1.8858557447E+01 6.4035361843E+00 + 1.3906948077E-01 1.8797353107E+01 1.2529954509E+01 + 1.8830702700E+01 6.2686470971E+00 1.8797978694E+01 + 6.5544595526E-02 6.3806279780E+00 6.2899537138E+00 + 1.8863574095E+01 6.3736390969E+00 1.2581421441E+01 + 1.8734401242E+01 1.2471618731E+01 5.4873935264E-02 + 1.5460124122E-02 1.2621309085E+01 6.3778516366E+00 + 1.0081842518E-01 1.2496207159E+01 1.2623889713E+01 + 6.2063436457E+00 1.8885827482E+01 1.8762944619E+01 + 6.3034865496E+00 3.7164154700E-03 6.2331379851E+00 + 6.3113811546E+00 1.8792894627E+01 1.2683755282E+01 + 6.4041646600E+00 6.2874778102E+00 7.8700288374E-02 + 6.4529977382E+00 6.3687812517E+00 6.2862863675E+00 + 6.1468143126E+00 6.4151528085E+00 1.2531901791E+01 + 6.3037337907E+00 1.2421065937E+01 1.8878527725E+01 + 6.2244594442E+00 1.2717452753E+01 6.2911158701E+00 + 6.2611259032E+00 1.2596072125E+01 1.2504892207E+01 + 1.2636570410E+01 3.7605457314E-02 7.2855281327E-02 + 1.2518933156E+01 1.8882710046E+01 6.2545679011E+00 +:V: + -2.0656547434E-05 6.8875753271E-04 4.3817863217E-04 + 2.6631889964E-05 -1.5930385978E-04 5.1404440647E-04 + 6.9240131774E-04 -4.5321897865E-04 -3.0937418646E-04 + -2.7091439368E-04 -1.3825200601E-04 -4.4575552252E-04 + 3.4000704465E-04 4.0282607424E-04 -3.1834075753E-05 + -1.0772647671E-04 3.7238773698E-04 -5.8500695333E-05 + -7.3209168733E-04 -5.9229298921E-04 2.6389716193E-04 + 1.0198326965E-04 1.3178488347E-04 3.8912557831E-04 + 5.1264280584E-04 -4.7167524381E-04 1.4414391811E-04 + -4.3632610438E-04 -2.2869170959E-05 -6.1634947872E-04 + 3.9090565032E-05 1.5525428765E-05 -3.0780291340E-04 + 4.2949864456E-05 -4.7588287134E-04 4.3691967196E-04 + 4.8892147348E-04 -4.4784819683E-05 3.8050901962E-04 + 7.2258303317E-04 3.4321334338E-04 -5.0989800622E-05 + -7.5289328397E-04 5.7151351871E-04 -2.9996241132E-04 + 5.2812984460E-06 -8.3470774441E-04 -5.6615679797E-05 + -3.7732712246E-04 5.9552778197E-04 -2.6706143343E-05 + -2.0336328160E-04 9.1404481706E-06 -4.2852118076E-04 + 2.1172516949E-04 1.7976234780E-04 4.1180731183E-04 + -3.7165478481E-04 -3.9786916601E-05 -2.6445747188E-04 +:F: + -3.4771632362E-03 3.8174299664E-03 1.1925246431E-03 + -1.7523067308E-03 -1.6959336173E-03 1.2345882768E-03 + 1.1723402875E-02 -1.7596879386E-03 -2.1483252732E-03 + 1.1317966391E-02 -1.3022195990E-03 -6.7796677992E-04 + 1.1979319842E-02 1.0382753823E-03 9.7909680417E-04 + 1.4329852582E-02 3.0657185899E-03 3.8229765092E-04 + 1.0985432318E-02 -2.7551247749E-03 1.3703975684E-04 + 1.3544512485E-02 7.1450795938E-04 8.0766420965E-05 + 1.4004288308E-02 -1.0257315664E-03 -5.8984118176E-04 + -5.6179238573E-04 1.9512014856E-03 -2.3754277120E-03 + 5.4777855134E-03 -1.6971137183E-03 -1.0457985309E-03 + -1.1673981247E-02 -2.6059939299E-03 3.0153387275E-03 + -1.1414172298E-02 1.0168159435E-03 1.6630176070E-03 + -1.1694711292E-02 -8.4695542212E-04 -1.1047654271E-04 + -1.4304114070E-02 2.8821799134E-03 -2.1287346683E-03 + -1.1387961297E-02 -2.6734192900E-03 8.5962261576E-04 + -1.3405711842E-02 2.0353164039E-03 6.4700346489E-04 + -1.4196593250E-02 -2.3497857059E-04 -1.2817211696E-03 + 3.1579707001E-03 -2.6460778342E-04 1.3869901839E-02 + -2.6520233656E-03 3.4032056623E-04 -1.3702905949E-02 +:ANGLES: + 90.001 89.999 90.000 +:VOLUME: 6.7419008312E+03 +:LATVEC_SCALE: + 1.8891939530E+01 1.8891237959E+01 1.8890584458E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.0054644443E-05 9.9999999995E-01 0.0000000000E+00 + 1.7818779741E-05 -3.8831233164E-06 9.9999999983E-01 +:STRIO: + 7.0342521330E-01 -8.8905310200E-02 1.4106635135E-01 + -8.8905310200E-02 7.2033996140E-01 -2.6910310238E-02 + 1.4106635135E-01 -2.6910310238E-02 4.7090937508E-01 +:STRESS: + 4.9055078399E+00 -8.6621518511E-03 2.2144095795E-03 + -8.6621518511E-03 5.5254120404E+00 7.6526153528E-03 + 2.2144095795E-03 7.6526153528E-03 5.8214008667E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.2020826266E+00 -8.0243158349E-02 1.3885194177E-01 + -8.0243158349E-02 -4.8050720790E+00 -3.4562925591E-02 + 1.3885194177E-01 -3.4562925591E-02 -5.3504914916E+00 +:PRESIO: 6.3155818326E-01 +:PRES: -5.4174402490E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7858820657E+00 +:PRESIG: 6.6479808764E-01 +:MIND: +Al - Al: 6.0808068857E+00 +C - C: 6.1830772794E+00 +Al - C: 6.2154958637E+00 + + +:MDSTEP: 7 +:MDTM: 15.65 +:TWIST: 0 +:TEL: 2400 +:TIO: 2401.99351139993 +:TEN: -2.6052887524E+00 +:KEN: 1.0839491679E-02 +:KENIG: 1.1409991241E-02 +:FEN: -2.6161282441E+00 +:UEN: -2.6090102102E+00 +:TSEN: -7.1180339028E-03 +:NPT_NP_HAMIL: 1.6218782738E-04 +:SNOSE[0]: 1.0157909945E+00 +:SNOSE[1]: 1.2356077632E-04 +:R: + 1.8886055995E+01 1.7069156411E-01 1.0888840395E-01 + 7.4705337636E-03 1.8849517873E+01 6.4238323735E+00 + 1.6781420758E-01 1.8776193809E+01 1.2515370936E+01 + 1.8817699536E+01 6.2620858408E+00 1.8776901620E+01 + 7.9780625098E-02 6.3964190177E+00 6.2877584222E+00 + 1.8857301517E+01 6.3882010516E+00 1.2577216361E+01 + 1.8702230413E+01 1.2445545224E+01 6.5747360186E-02 + 1.9891456078E-02 1.2625115838E+01 6.3929818542E+00 + 1.2222322880E-01 1.2475112279E+01 1.2628015540E+01 + 6.1876982710E+00 1.8882451874E+01 1.8734810580E+01 + 6.3045213404E+00 4.3163725019E-03 6.2195391959E+00 + 6.3122464269E+00 1.8770786629E+01 1.2700004399E+01 + 6.4233695641E+00 6.2848380598E+00 9.4403951725E-02 + 6.4818693039E+00 6.3820836533E+00 6.2832830475E+00 + 6.1148934434E+00 6.4379152071E+00 1.2517706270E+01 + 6.3031229362E+00 1.2384976100E+01 1.8873507674E+01 + 6.2079571179E+00 1.2740387775E+01 6.2891260526E+00 + 6.2518227822E+00 1.2594799733E+01 1.2485415516E+01 + 1.2643985723E+01 4.5000791221E-02 9.0361018270E-02 + 1.2502052533E+01 1.8878637320E+01 6.2422377291E+00 +:V: + -2.3492898189E-05 6.8864055046E-04 4.3695324715E-04 + 2.5147629919E-05 -1.6002027218E-04 5.1249962495E-04 + 6.9856240376E-04 -4.5246135271E-04 -3.0972378471E-04 + -2.6011002517E-04 -1.3869129173E-04 -4.4404462600E-04 + 3.4821642991E-04 4.0167539997E-04 -3.0759134799E-05 + -9.5059146787E-05 3.7324516276E-04 -5.7836291996E-05 + -7.1914440255E-04 -5.9174696841E-04 2.6263058205E-04 + 1.1288467947E-04 1.3172859647E-04 3.8716665969E-04 + 5.2172507011E-04 -4.7012890421E-04 1.4283450256E-04 + -4.3478919033E-04 -2.0951103164E-05 -6.1531272221E-04 + 4.3667775619E-05 1.3886789347E-05 -3.0711980346E-04 + 3.2943992340E-05 -4.7577514160E-04 4.3737822456E-04 + 4.7687023198E-04 -4.3595944412E-05 3.8002884349E-04 + 7.0903069923E-04 3.4064830566E-04 -5.0827501669E-05 + -7.6098945162E-04 5.7115722161E-04 -3.0033434772E-04 + -4.2024235730E-06 -8.3279294846E-04 -5.5536938409E-05 + -3.8663757440E-04 5.9423698685E-04 -2.5962203415E-05 + -2.1426092900E-04 8.8840592081E-06 -4.2744167447E-04 + 2.1711753506E-04 1.7827974148E-04 4.3625731523E-04 + -3.7518085247E-04 -3.8866092630E-05 -2.8932610374E-04 +:F: + -3.5495342927E-03 4.5508245405E-03 1.3682907937E-03 + -1.4541138337E-03 -2.0130850823E-03 1.5182320181E-03 + 1.1695340572E-02 -2.1299759911E-03 -2.5455237319E-03 + 1.1047093367E-02 -1.4788118698E-03 -8.2662245745E-04 + 1.1888242365E-02 1.2710467036E-03 1.1904796651E-03 + 1.4533630602E-02 3.6555347891E-03 4.6668169622E-04 + 1.0684087190E-02 -3.3711939955E-03 1.3616637299E-04 + 1.3747044876E-02 8.0480194570E-04 1.2048454381E-04 + 1.4119332492E-02 -1.2127937035E-03 -7.1769877322E-04 + -1.2647471700E-03 2.3408036739E-03 -2.8764066792E-03 + 5.9332608243E-03 -2.0167947010E-03 -1.1784214101E-03 + -1.1656381480E-02 -3.1119212902E-03 3.5516780445E-03 + -1.1179922097E-02 1.2517456820E-03 1.9645882855E-03 + -1.1537656103E-02 -9.6926879961E-04 -1.2989753474E-04 + -1.4492452151E-02 3.4504966766E-03 -2.5294884575E-03 + -1.1171617020E-02 -3.2387839698E-03 1.0077327276E-03 + -1.3558049904E-02 2.3664310453E-03 7.8409074265E-04 + -1.4362854030E-02 -2.5979448546E-04 -1.5127087706E-03 + 3.7542296637E-03 -3.0588351689E-04 1.4391905535E-02 + -3.1749338704E-03 4.1662234843E-04 -1.4183562611E-02 +:ANGLES: + 90.001 89.999 90.000 +:VOLUME: 6.7393005901E+03 +:LATVEC_SCALE: + 1.8889791956E+01 1.8888801316E+01 1.8887881717E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.4178346560E-05 9.9999999990E-01 0.0000000000E+00 + 2.5045598695E-05 -5.5215547974E-06 9.9999999967E-01 +:STRIO: + 7.0203494106E-01 -9.1247854778E-02 1.4182451191E-01 + -9.1247854778E-02 7.1838398228E-01 -2.6436097590E-02 + 1.4182451191E-01 -2.6436097590E-02 4.7241164898E-01 +:STRESS: + 4.8919524758E+00 -1.0562372868E-02 7.7430546506E-04 + -1.0562372868E-02 5.5183570642E+00 1.0390985946E-02 + 7.7430546506E-04 1.0390985946E-02 5.8254250751E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1899175347E+00 -8.0685481910E-02 1.4105020644E-01 + -8.0685481910E-02 -4.7999730819E+00 -3.6827083536E-02 + 1.4105020644E-01 -3.6827083536E-02 -5.3530134261E+00 +:PRESIO: 6.3094352411E-01 +:PRES: -5.4119115384E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7809680142E+00 +:PRESIG: 6.6415107801E-01 +:MIND: +Al - Al: 6.0371240681E+00 +C - C: 6.1538653239E+00 +Al - C: 6.1975900588E+00 + + +:MDSTEP: 8 +:MDTM: 17.85 +:TWIST: 0 +:TEL: 2400 +:TIO: 2401.92499257598 +:TEN: -2.6054294204E+00 +:KEN: 1.0839182473E-02 +:KENIG: 1.1409665762E-02 +:FEN: -2.6162686028E+00 +:UEN: -2.6091765448E+00 +:TSEN: -7.0920579882E-03 +:NPT_NP_HAMIL: 2.6071284087E-04 +:SNOSE[0]: 1.0214515471E+00 +:SNOSE[1]: 1.2460961636E-04 +:R: + 1.8882505388E+01 1.9913043193E-01 1.2690495083E-01 + 8.4441913777E-03 1.8840016546E+01 6.4439030650E+00 + 1.9680539112E-01 1.8754635009E+01 1.2500454394E+01 + 1.8804786671E+01 6.2553568718E+00 1.8755424686E+01 + 9.4352263542E-02 6.4120162031E+00 6.2854532653E+00 + 1.8851193925E+01 6.4026564488E+00 1.2572724370E+01 + 1.8670215319E+01 1.2419207779E+01 7.6564260185E-02 + 2.4773377473E-02 1.2628633073E+01 6.4078673118E+00 + 1.4400482441E-01 1.2453796085E+01 1.2631766112E+01 + 6.1689955117E+00 1.8878729245E+01 1.8706245567E+01 + 6.3056355886E+00 4.8409304932E-03 6.2058129235E+00 + 6.3125771342E+00 1.8748250204E+01 1.2715957878E+01 + 6.4419460913E+00 6.2821096968E+00 1.1008684802E-01 + 6.5100538680E+00 6.3951286400E+00 6.2801285542E+00 + 6.0825323947E+00 6.4605177015E+00 1.2503176645E+01 + 6.3020156763E+00 1.2348676922E+01 1.8868060508E+01 + 6.1909473989E+00 1.2762979687E+01 6.2870113545E+00 + 6.2419523907E+00 1.2593227421E+01 1.2465669588E+01 + 1.2651394713E+01 5.2330643124E-02 1.0888836049E-01 + 1.2484756037E+01 1.8874177137E+01 6.2287095463E+00 +:V: + -2.6376009564E-05 6.8904012152E-04 4.3582651001E-04 + 2.3918987959E-05 -1.6097385740E-04 5.1112993777E-04 + 7.0457129635E-04 -4.5196087664E-04 -3.1035975236E-04 + -2.4956001552E-04 -1.3925153686E-04 -4.4240958265E-04 + 3.5626231510E-04 4.0067056616E-04 -2.9510829508E-05 + -8.2278845227E-05 3.7453648900E-04 -5.7096853137E-05 + -7.0642163069E-04 -5.9164335032E-04 2.6133671972E-04 + 1.2388219084E-04 1.3173096520E-04 3.8520322840E-04 + 5.3078084782E-04 -4.6868193642E-04 1.4140506113E-04 + -4.3378324918E-04 -1.8714457266E-05 -6.1461237017E-04 + 4.8597682623E-05 1.1991376560E-05 -3.0651153122E-04 + 2.3002659312E-05 -4.7602726986E-04 4.3821516481E-04 + 4.6501776186E-04 -4.2214411805E-05 3.7975298246E-04 + 6.9558790427E-04 3.3795121566E-04 -5.0679008999E-05 + -7.6909555935E-04 5.7120056952E-04 -3.0099606194E-04 + -1.3455855739E-05 -8.3125148232E-04 -5.4333249034E-05 + -3.9597167730E-04 5.9314961999E-04 -2.5105716922E-05 + -2.2520741337E-04 8.6118950338E-06 -4.2650370533E-04 + 2.2356049655E-04 1.7670886914E-04 4.6154534146E-04 + -3.7962119001E-04 -3.7799524843E-05 -3.1496970723E-04 +:F: + -3.6321667995E-03 5.2580901332E-03 1.5420203223E-03 + -1.1535589592E-03 -2.3196493181E-03 1.7858609223E-03 + 1.1656206612E-02 -2.5025900861E-03 -2.9257626675E-03 + 1.0767962267E-02 -1.6383010531E-03 -9.7022568903E-04 + 1.1802223104E-02 1.4931881096E-03 1.3980724619E-03 + 1.4731319118E-02 4.2255082340E-03 5.5211578572E-04 + 1.0391100512E-02 -3.9826619982E-03 1.3273892619E-04 + 1.3947897957E-02 8.9351725794E-04 1.6112133092E-04 + 1.4219240776E-02 -1.3873219557E-03 -8.4801010081E-04 + -1.9443222047E-03 2.7300172594E-03 -3.3498195859E-03 + 6.3911821897E-03 -2.3264720596E-03 -1.3070956245E-03 + -1.1637324016E-02 -3.6079710145E-03 4.0547580908E-03 + -1.0945228170E-02 1.4775986686E-03 2.2590530879E-03 + -1.1385553610E-02 -1.0920218566E-03 -1.5482300640E-04 + -1.4667832862E-02 4.0064473378E-03 -2.9173907981E-03 + -1.0960737193E-02 -3.7931906204E-03 1.1552984303E-03 + -1.3701148808E-02 2.6859493605E-03 9.1536258620E-04 + -1.4518729347E-02 -2.7270365119E-04 -1.7341294148E-03 + 4.3344748428E-03 -3.4279166067E-04 1.4955953717E-02 + -3.6950054073E-03 4.9535891329E-04 -1.4705098774E-02 +:ANGLES: + 90.001 89.998 90.000 +:VOLUME: 6.7362459813E+03 +:LATVEC_SCALE: + 1.8887270638E+01 1.8885937778E+01 1.8884703906E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -1.9048059489E-05 9.9999999982E-01 0.0000000000E+00 + 3.3576746108E-05 -7.4989217651E-06 9.9999999941E-01 +:STRIO: + 7.0169908118E-01 -9.3669710087E-02 1.4292227936E-01 + -9.3669710087E-02 7.1726960758E-01 -2.6017254443E-02 + 1.4292227936E-01 -2.6017254443E-02 4.7466618488E-01 +:STRESS: + 4.8773531654E+00 -1.2517676033E-02 -1.3898366344E-03 + -1.2517676033E-02 5.5094635612E+00 1.3420167372E-02 + -1.3898366344E-03 1.3420167372E-02 5.8295072331E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1756540843E+00 -8.1152034055E-02 1.4431211599E-01 + -8.1152034055E-02 -4.7921939536E+00 -3.9437421815E-02 + 1.4431211599E-01 -3.9437421815E-02 -5.3548410482E+00 +:PRESIO: 6.3121162455E-01 +:PRES: -5.4054413199E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7742296954E+00 +:PRESIG: 6.6443328900E-01 +:MIND: +Al - Al: 5.9934286562E+00 +C - C: 6.1225665225E+00 +Al - C: 6.1791856978E+00 + + +:MDSTEP: 9 +:MDTM: 17.82 +:TWIST: 0 +:TEL: 2400 +:TIO: 2405.4600251057 +:TEN: -2.6055730885E+00 +:KEN: 1.0855135038E-02 +:KENIG: 1.1426457934E-02 +:FEN: -2.6164282235E+00 +:UEN: -2.6093658128E+00 +:TSEN: -7.0624107532E-03 +:NPT_NP_HAMIL: 4.0088638800E-04 +:SNOSE[0]: 1.0271994181E+00 +:SNOSE[1]: 1.2967292782E-04 +:R: + 1.8878455626E+01 2.2758761633E-01 1.4487082910E-01 + 9.3666685303E-03 1.8830036689E+01 6.4637521918E+00 + 2.2603700407E-01 1.8732658712E+01 1.2485187664E+01 + 1.8791948691E+01 6.2484526333E+00 1.8733536255E+01 + 1.0925305637E-01 6.4274228541E+00 6.2830424203E+00 + 1.8845250783E+01 6.4170201124E+00 1.2567942792E+01 + 1.8638340926E+01 1.2392583572E+01 8.7323416503E-02 + 3.0109886028E-02 1.2631858318E+01 6.4225048699E+00 + 1.6616239063E-01 1.2432249645E+01 1.2635130627E+01 + 6.1502125360E+00 1.8874665169E+01 1.8677227646E+01 + 6.3068423137E+00 5.2795232272E-03 6.1919533240E+00 + 6.3123746723E+00 1.8725263314E+01 1.2731624831E+01 + 6.4599008027E+00 6.2792981468E+00 1.2575718541E-01 + 6.5375545505E+00 6.4079082727E+00 6.2768193375E+00 + 6.0497295336E+00 6.4829738551E+00 1.2488295482E+01 + 6.3004205132E+00 1.2312147973E+01 1.8862182676E+01 + 6.1734277179E+00 1.2785231838E+01 6.2847734143E+00 + 6.2315115248E+00 1.2591349730E+01 1.2445643057E+01 + 1.2658836472E+01 5.9591541609E-02 1.2847307920E-01 + 1.2467002352E+01 1.8869328423E+01 6.2139472970E+00 +:V: + -2.9317042367E-05 6.8999604902E-04 4.3483780656E-04 + 2.2948998579E-05 -1.6216970834E-04 5.0997010059E-04 + 7.1048625117E-04 -4.5176140778E-04 -3.1129544422E-04 + -2.3929613751E-04 -1.3993045341E-04 -4.4088854746E-04 + 3.6418198591E-04 3.9984066853E-04 -2.8096536499E-05 + -6.9402815646E-05 3.7627830791E-04 -5.6287633803E-05 + -6.9398479925E-04 -5.9203169405E-04 2.6003887530E-04 + 1.3498329987E-04 1.3180279481E-04 3.8327365109E-04 + 5.3984583924E-04 -4.6736911975E-04 1.3986829017E-04 + -4.3332712265E-04 -1.6163214616E-05 -6.1428055789E-04 + 5.3883648979E-05 9.8512126049E-06 -3.0600459574E-04 + 1.3130805379E-05 -4.7667450285E-04 4.3944117125E-04 + 4.5341046455E-04 -4.0655647873E-05 3.7971011306E-04 + 6.8231965917E-04 3.3515524956E-04 -5.0553054963E-05 + -7.7727158782E-04 5.7168560637E-04 -3.0196375113E-04 + -2.2484953878E-05 -8.3015015058E-04 -5.3011484147E-05 + -4.0535768009E-04 5.9231192099E-04 -2.4144191369E-05 + -2.3621234227E-04 8.3349864830E-06 -4.2574004113E-04 + 2.3103817123E-04 1.7507574537E-04 4.8778715199E-04 + -3.8499866087E-04 -3.6587056245E-05 -3.4148833436E-04 +:F: + -3.7271652677E-03 5.9348556624E-03 1.7120954807E-03 + -8.5095995327E-04 -2.6154477769E-03 2.0363834604E-03 + 1.1606369367E-02 -2.8766956661E-03 -3.2872025589E-03 + 1.0480702240E-02 -1.7792701505E-03 -1.1082352442E-03 + 1.1720247646E-02 1.7045809646E-03 1.6015291852E-03 + 1.4920803101E-02 4.7749476391E-03 6.3845794394E-04 + 1.0109049516E-02 -4.5865695976E-03 1.2636692467E-04 + 1.4146674612E-02 9.8001024551E-04 2.0279542171E-04 + 1.4301789229E-02 -1.5502104530E-03 -9.8018569526E-04 + -2.5988943871E-03 3.1196275282E-03 -3.7900532438E-03 + 6.8505532905E-03 -2.6244799147E-03 -1.4330089908E-03 + -1.1617438363E-02 -4.0932412555E-03 4.5209422453E-03 + -1.0710559881E-02 1.6886149230E-03 2.5441134863E-03 + -1.1238603301E-02 -1.2158920989E-03 -1.8353381600E-04 + -1.4826846521E-02 4.5489450645E-03 -3.2917288434E-03 + -1.0757245253E-02 -4.3308170105E-03 1.3016969083E-03 + -1.3834962027E-02 2.9931243700E-03 1.0420101604E-03 + -1.4662365781E-02 -2.7346944029E-04 -1.9465888145E-03 + 4.8984679717E-03 -3.7539328911E-04 1.5563834327E-02 + -4.2096162379E-03 5.7678025590E-04 -1.5269688337E-02 +:ANGLES: + 90.001 89.998 90.001 +:VOLUME: 6.7327298784E+03 +:LATVEC_SCALE: + 1.8884370118E+01 1.8882640356E+01 1.8881042335E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -2.4682329254E-05 9.9999999970E-01 0.0000000000E+00 + 4.3466766737E-05 -9.8452561322E-06 9.9999999901E-01 +:STRIO: + 7.0252606976E-01 -9.6190079494E-02 1.4439386613E-01 + -9.6190079494E-02 7.1710855525E-01 -2.5659847130E-02 + 1.4439386613E-01 -2.5659847130E-02 4.7777759320E-01 +:STRESS: + 4.8616470958E+00 -1.4526732644E-02 -4.2841062031E-03 + -1.4526732644E-02 5.4986732518E+00 1.6761067824E-02 + -4.2841062031E-03 1.6761067824E-02 5.8336129525E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1591210261E+00 -8.1663346850E-02 1.4867797233E-01 + -8.1663346850E-02 -4.7815646965E+00 -4.2420914954E-02 + 1.4867797233E-01 -4.2420914954E-02 -5.3558353593E+00 +:PRESIO: 6.3247073940E-01 +:PRES: -5.3979777667E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7655070273E+00 +:PRESIG: 6.6575867306E-01 +:MIND: +Al - Al: 5.9496899331E+00 +C - C: 6.0891193269E+00 +Al - C: 6.1602280221E+00 + + +:MDSTEP: 10 +:MDTM: 16.66 +:TWIST: 0 +:TEL: 2400 +:TIO: 2410.49301684657 +:TEN: -2.6057305852E+00 +:KEN: 1.0877847452E-02 +:KENIG: 1.1450365739E-02 +:FEN: -2.6166084327E+00 +:UEN: -2.6095793101E+00 +:TSEN: -7.0291225690E-03 +:NPT_NP_HAMIL: 5.5413286230E-04 +:SNOSE[0]: 1.0334755623E+00 +:SNOSE[1]: 1.4774235164E-04 +:R: + 1.8873898422E+01 2.5607802354E-01 1.6278686138E-01 + 1.0248556766E-02 1.8819562375E+01 6.4833792516E+00 + 2.5549787394E-01 1.8710249290E+01 1.2469555736E+01 + 1.8779171107E+01 6.2413668915E+00 1.8711226923E+01 + 1.2447419450E-01 6.4426389105E+00 6.2805297268E+00 + 1.8839471109E+01 6.4313031754E+00 1.2562868686E+01 + 1.8606596585E+01 1.2365653751E+01 9.8021751297E-02 + 3.5903864957E-02 1.2634787631E+01 6.4368885008E+00 + 1.8869084103E-01 1.2410467124E+01 1.2638096657E+01 + 6.1313304700E+00 1.8870264476E+01 1.8647739336E+01 + 6.3081539490E+00 5.6219822095E-03 6.1779564295E+00 + 6.3116404510E+00 1.8701806914E+01 1.2747009326E+01 + 6.4772370802E+00 6.2764083075E+00 1.4142019838E-01 + 6.5643696771E+00 6.4204120990E+00 6.2733517392E+00 + 6.0164891859E+00 6.5052924733E+00 1.2473047321E+01 + 6.2983459681E+00 1.2275374613E+01 1.8855869931E+01 + 6.1553986013E+00 1.2807142584E+01 6.2824135135E+00 + 6.2204991366E+00 1.2589161065E+01 1.2425327155E+01 + 1.2666346521E+01 6.6779193044E-02 1.4915042314E-01 + 1.2448753153E+01 1.8864089818E+01 6.1979141706E+00 +:V: + -3.2313040424E-05 6.9118552396E-04 4.3379841646E-04 + 2.2228143584E-05 -1.6352848906E-04 5.0878831714E-04 + 7.1599640777E-04 -4.5167032798E-04 -3.1238040134E-04 + -2.2922442908E-04 -1.4065181753E-04 -4.3928966647E-04 + 3.7182262492E-04 3.9900643244E-04 -2.6509223240E-05 + -5.6412806789E-05 3.7829004665E-04 -5.5384629860E-05 + -6.8153223419E-04 -5.9265089179E-04 2.5862471361E-04 + 1.4612502496E-04 1.3188607346E-04 3.8121688381E-04 + 5.4867365461E-04 -4.6598192358E-04 1.3816411346E-04 + -4.3321318916E-04 -1.3292774740E-05 -6.1402434266E-04 + 5.9500985786E-05 7.4746137568E-06 -3.0546676645E-04 + 3.3252889302E-06 -4.7750247725E-04 4.4083424689E-04 + 4.4185736810E-04 -3.8918416748E-05 3.7972903982E-04 + 6.6893478586E-04 3.3211848763E-04 -5.0430553851E-05 + -7.8517094622E-04 5.7235551528E-04 -3.0309566326E-04 + -3.1284906930E-05 -8.2911827808E-04 -5.1551002548E-05 + -4.1461279050E-04 5.9146067536E-04 -2.3071858299E-05 + -2.4716174964E-04 8.0595321514E-06 -4.2496213481E-04 + 2.3941348664E-04 1.7331392278E-04 5.1484825393E-04 + -3.9113143824E-04 -3.5208485338E-05 -3.6880848859E-04 +:F: + -3.8351377016E-03 6.5779380102E-03 1.8764476429E-03 + -5.4711495903E-04 -2.9007568112E-03 2.2687848528E-03 + 1.1547147925E-02 -3.2506582862E-03 -3.6276594609E-03 + 1.0186683285E-02 -1.9004885757E-03 -1.2404925617E-03 + 1.1641729940E-02 1.9052048628E-03 1.8006457938E-03 + 1.5101672118E-02 5.3017872173E-03 7.2570935355E-04 + 9.8381423440E-03 -5.1807388970E-03 1.1705341364E-04 + 1.4342621510E-02 1.0645656705E-03 2.4612890758E-04 + 1.4366242586E-02 -1.7009837803E-03 -1.1145849493E-03 + -3.2285316013E-03 3.5093080063E-03 -4.1905402881E-03 + 7.3123287607E-03 -2.9090058386E-03 -1.5566342369E-03 + -1.1598253526E-02 -4.5656671133E-03 4.9446982568E-03 + -1.0477225083E-02 1.8796740851E-03 2.8171995919E-03 + -1.1097368874E-02 -1.3413102109E-03 -2.1426958691E-04 + -1.4968150794E-02 5.0767059440E-03 -3.6516971813E-03 + -1.0560695296E-02 -4.8457099061E-03 1.4473032751E-03 + -1.3959042704E-02 3.2866460700E-03 1.1644462944E-03 + -1.4793454028E-02 -2.6334439402E-04 -2.1506541667E-03 + 5.4455123461E-03 -4.0489165159E-04 1.6217757333E-02 + -4.7171062477E-03 6.6172559882E-04 -1.5879642284E-02 +:ANGLES: + 90.002 89.997 90.001 +:VOLUME: 6.7287444336E+03 +:LATVEC_SCALE: + 1.8881084353E+01 1.8878901392E+01 1.8876887340E+01 +:LatVec: + 1.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + -3.1102039177E-05 9.9999999952E-01 0.0000000000E+00 + 5.4784363799E-05 -1.2595511275E-05 9.9999999842E-01 +:STRIO: + 7.0389109557E-01 -9.8728505596E-02 1.4612358071E-01 + -9.8728505596E-02 7.1726283767E-01 -2.5343827232E-02 + 1.4612358071E-01 -2.5343827232E-02 4.8135446959E-01 +:STRESS: + 4.8449410758E+00 -1.6568661948E-02 -7.9184577867E-03 + -1.6568661948E-02 5.4859304473E+00 2.0392135441E-02 + -7.9184577867E-03 2.0392135441E-02 5.8378199911E+00 +:CONSTRESS: + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 + 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 +:TOTSTRESS: + -4.1410499802E+00 -8.2159843649E-02 1.5404203849E-01 + -8.2159843649E-02 -4.7686676096E+00 -4.5735962673E-02 + 1.5404203849E-01 -4.5735962673E-02 -5.3564655215E+00 +:PRESIO: 6.3416946761E-01 +:PRES: -5.3895638381E+00 +:CONPRES: 0.0000000000E+00 +:TOTPRES: -4.7553943705E+00 +:PRESIG: 6.6754680801E-01 +:MIND: +Al - Al: 5.9058872561E+00 +C - C: 6.0534637367E+00 +Al - C: 6.1406664112E+00 diff --git a/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.refout b/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.refout new file mode 100644 index 00000000..5ee2e94b --- /dev/null +++ b/tests/Al18C2_NPTNP_full_flex/standard/Al18C2_NPTNP_full_flex.refout @@ -0,0 +1,648 @@ +*************************************************************************** +* SPARC (version December 03, 2025) * +* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * +* Distributed under GNU General Public License 3 (GPL) * +* Start time: Sun Apr 5 12:57:36 2026 * +*************************************************************************** + Input parameters +*************************************************************************** +LATVEC_SCALE: 18.897259886 18.897259886 18.897259886 +LATVEC: +1.000000000000000 0.000000000000000 0.000000000000000 +0.000000000000000 1.000000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 +WARNING: This system is cuboidal. To get the best performance, please align the lattice vectors onto standard cartesian coordinate. +FD_GRID: 76 76 76 +FD_ORDER: 12 +BC: P P P +KPOINT_GRID: 1 1 1 +KPOINT_SHIFT: 0 0 0 +SPIN_TYP: 0 +ELEC_TEMP_TYPE: Fermi-Dirac +ELEC_TEMP: 2400 +EXCHANGE_CORRELATION: GGA_PBE +HUBBARD_FLAG: 0 +NSTATES: 80 +CHEB_DEGREE: 30 +CHEFSI_BOUND_FLAG: 0 +CALC_STRESS: 1 +TWTIME: 1E+09 +MD_FLAG: 1 +MD_METHOD: NPT_NP +MD_TIMESTEP: 1 +MD_NSTEP: 10 +ION_VEL_DSTR: 2 +ION_VEL_DSTR_RAND: 0 +ION_TEMP: 2400 +NPT_SCALE_VECS: 1 2 3 +NPT_SCALE_CONSTRAINTS: none +NPT_NP_ANGLES: 1 +NPT_NP_QMASS: 2000 +NPT_NP_BMASS: 0.5 +TARGET_STRESS: 0.1 0.1 0.1 0 0 0 GPa +MAXIT_SCF: 100 +MINIT_SCF: 2 +MAXIT_POISSON: 3000 +TOL_SCF: 1.00E-06 +POISSON_SOLVER: AAR +TOL_POISSON: 1.00E-08 +TOL_LANCZOS: 1.00E-02 +TOL_PSEUDOCHARGE: 1.00E-09 +MIXING_VARIABLE: density +MIXING_PRECOND: kerker +TOL_PRECOND: 6.18E-05 +PRECOND_KERKER_KTF: 1 +PRECOND_KERKER_THRESH: 0 +MIXING_PARAMETER: 1 +MIXING_HISTORY: 7 +PULAY_FREQUENCY: 1 +PULAY_RESTART: 0 +REFERENCE_CUTOFF: 0.5 +RHO_TRIGGER: 4 +NUM_CHEFSI: 1 +FIX_RAND: 0 +VERBOSITY: 1 +PRINT_FORCES: 1 +PRINT_ATOMS: 1 +PRINT_EIGEN: 0 +PRINT_DENSITY: 0 +PRINT_MDOUT: 1 +PRINT_VELS: 1 +PRINT_RESTART: 1 +PRINT_RESTART_FQ: 1 +PRINT_ENERGY_DENSITY: 0 +OUTPUT_FILE: Al18C2_NPTNP_full_flex +*************************************************************************** + Cell +*************************************************************************** +Lattice vectors (Bohr): +18.897259886000001 0.000000000000000 0.000000000000000 +0.000000000000000 18.897259886000001 0.000000000000000 +0.000000000000000 0.000000000000000 18.897259886000001 +Volume: 6.7483330373E+03 (Bohr^3) +Density: 7.5528236408E-02 (amu/Bohr^3), 8.4635982984E-01 (g/cc) +*************************************************************************** + Parallelization +*************************************************************************** +NP_SPIN_PARAL: 1 +NP_KPOINT_PARAL: 1 +NP_BAND_PARAL: 80 +NP_DOMAIN_PARAL: 1 1 1 +NP_DOMAIN_PHI_PARAL: 4 4 5 +EIG_SERIAL_MAXNS: 1500 +*************************************************************************** + Initialization +*************************************************************************** +Number of processors : 80 +Mesh spacing : 0.248648 (Bohr) +Number of symmetry adapted k-points: 1 +Output printed to : Al18C2_NPTNP_full_flex.out_05 +MD output printed to : Al18C2_NPTNP_full_flex.aimd_05 +Total number of atom types : 2 +Total number of atoms : 20 +Total number of electrons : 62 +Atom type 1 (valence electrons) : Al 3 +Pseudopotential : ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 +Atomic mass : 26.9815385 +Pseudocharge radii of atom type 1 : 6.96 6.96 6.96 (x, y, z dir) +Number of atoms of type 1 : 18 +Atom type 2 (valence electrons) : C 4 +Pseudopotential : ../../../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 +Atomic mass : 12.011 +Pseudocharge radii of atom type 2 : 7.21 7.21 7.21 (x, y, z dir) +Number of atoms of type 2 : 2 +Estimated total memory usage : 1.97 GB +Estimated memory per processor : 25.24 MB +=================================================================== + Self Consistent Field (SCF#1) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6085048478E+00 2.222E-01 4.695 +2 -2.6455774974E+00 6.115E-01 1.387 +3 -2.6194565074E+00 3.648E-01 1.369 +4 -2.6234750168E+00 3.891E-01 1.350 +5 -2.6160846046E+00 1.010E-01 1.345 +6 -2.6159394181E+00 1.024E-01 1.325 +7 -2.6158575550E+00 8.390E-02 1.329 +8 -2.6157181717E+00 2.372E-02 1.350 +9 -2.6157407102E+00 3.414E-02 1.323 +10 -2.6157119342E+00 8.710E-03 1.318 +11 -2.6157127764E+00 9.141E-03 1.313 +12 -2.6157118757E+00 1.112E-03 1.311 +13 -2.6157122107E+00 4.284E-04 1.300 +14 -2.6157123232E+00 2.094E-04 1.293 +15 -2.6157123764E+00 1.136E-04 1.263 +16 -2.6157123822E+00 2.158E-04 1.257 +17 -2.6157123824E+00 7.035E-05 1.259 +18 -2.6157123846E+00 2.007E-05 1.250 +19 -2.6157123849E+00 1.344E-05 1.245 +20 -2.6157123872E+00 4.760E-06 1.228 +21 -2.6157123855E+00 2.448E-06 1.230 +22 -2.6157123873E+00 2.947E-06 1.210 +23 -2.6157123870E+00 7.583E-07 1.184 +Total number of SCF: 23 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157123870E+00 (Ha/atom) +Total free energy : -5.2314247740E+01 (Ha) +Band structure energy : -9.0952982482E+00 (Ha) +Exchange correlation energy : -2.0462262872E+01 (Ha) +Self and correction energy : -7.6945217010E+01 (Ha) +-Entropy*kb*T : -1.4401402155E-01 (Ha) +Fermi level : -2.8332769482E-02 (Ha) +RMS force : 1.0671799968E-02 (Ha/Bohr) +Maximum force : 1.3274747035E-02 (Ha/Bohr) +Time for force calculation : 0.046 (sec) +Pressure : -5.4299705565E+00 (GPa) +Maximum stress : 5.8022454141E+00 (GPa) +Time for stress calculation : 0.119 (sec) +MD step time : 33.857 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8969060750195 18.8968605602439 18.8968172756089 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248644 (Bohr) +Mesh spacing in y-direction : 0.248643 (Bohr) +Mesh spacing in z direction : 0.248642 (Bohr) +=================================================================== + Self Consistent Field (SCF#2) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159453515E+00 3.773E-02 1.384 +2 -2.6165149088E+00 1.886E-01 1.335 +3 -2.6157888243E+00 5.293E-02 1.324 +4 -2.6159246051E+00 9.229E-02 1.333 +5 -2.6157320278E+00 3.537E-03 1.313 +6 -2.6157309389E+00 2.134E-03 1.306 +7 -2.6157309953E+00 9.733E-04 1.304 +8 -2.6157312722E+00 5.229E-04 1.294 +9 -2.6157314826E+00 3.409E-04 1.287 +10 -2.6157316213E+00 1.557E-04 1.289 +11 -2.6157316722E+00 7.440E-05 1.253 +12 -2.6157316789E+00 5.415E-05 1.242 +13 -2.6157316799E+00 8.482E-05 1.231 +14 -2.6157316803E+00 1.822E-05 1.240 +15 -2.6157316807E+00 5.826E-06 1.225 +16 -2.6157316812E+00 3.152E-06 1.220 +17 -2.6157316811E+00 1.813E-06 1.203 +18 -2.6157316841E+00 1.394E-06 1.192 +19 -2.6157316825E+00 1.084E-06 1.179 +20 -2.6157316823E+00 2.594E-07 1.170 +Total number of SCF: 20 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157316823E+00 (Ha/atom) +Total free energy : -5.2314633645E+01 (Ha) +Band structure energy : -9.0959909345E+00 (Ha) +Exchange correlation energy : -2.0462741447E+01 (Ha) +Self and correction energy : -7.6945216544E+01 (Ha) +-Entropy*kb*T : -1.4390662031E-01 (Ha) +Fermi level : -2.8355613114E-02 (Ha) +RMS force : 1.0685582810E-02 (Ha/Bohr) +Maximum force : 1.3505709369E-02 (Ha/Bohr) +Time for force calculation : 0.046 (sec) +Pressure : -5.4296427178E+00 (GPa) +Maximum stress : 5.8059466318E+00 (GPa) +Time for stress calculation : 0.118 (sec) +MD step time : 25.896 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8961987971643 18.8960614348118 18.8959316278949 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248634 (Bohr) +Mesh spacing in y-direction : 0.248632 (Bohr) +Mesh spacing in z direction : 0.248631 (Bohr) +=================================================================== + Self Consistent Field (SCF#3) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159886653E+00 3.836E-02 1.382 +2 -2.6165807832E+00 1.902E-01 1.333 +3 -2.6158311697E+00 5.426E-02 1.321 +4 -2.6159687888E+00 9.339E-02 1.323 +5 -2.6157718208E+00 3.596E-03 1.311 +6 -2.6157706721E+00 2.211E-03 1.303 +7 -2.6157707106E+00 9.902E-04 1.300 +8 -2.6157709978E+00 5.319E-04 1.290 +9 -2.6157712193E+00 3.510E-04 1.289 +10 -2.6157713651E+00 1.593E-04 1.278 +11 -2.6157714187E+00 7.743E-05 1.267 +12 -2.6157714261E+00 5.859E-05 1.240 +13 -2.6157714270E+00 9.551E-05 1.228 +14 -2.6157714274E+00 1.798E-05 1.235 +15 -2.6157714279E+00 6.180E-06 1.221 +16 -2.6157714287E+00 3.594E-06 1.218 +17 -2.6157714284E+00 2.276E-06 1.200 +18 -2.6157714308E+00 1.764E-06 1.193 +19 -2.6157714303E+00 8.042E-07 1.177 +Total number of SCF: 19 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6157714303E+00 (Ha/atom) +Total free energy : -5.2315428606E+01 (Ha) +Band structure energy : -9.0967763383E+00 (Ha) +Exchange correlation energy : -2.0463958888E+01 (Ha) +Self and correction energy : -7.6945216223E+01 (Ha) +-Entropy*kb*T : -1.4373364337E-01 (Ha) +Fermi level : -2.8386587858E-02 (Ha) +RMS force : 1.0744085813E-02 (Ha/Bohr) +Maximum force : 1.3772561427E-02 (Ha/Bohr) +Time for force calculation : 0.046 (sec) +Pressure : -5.4282078308E+00 (GPa) +Maximum stress : 5.8097443730E+00 (GPa) +Time for stress calculation : 0.118 (sec) +MD step time : 24.658 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8951374388507 18.8948609604214 18.8946011273613 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.24862 (Bohr) +Mesh spacing in y-direction : 0.248617 (Bohr) +Mesh spacing in z direction : 0.248613 (Bohr) +=================================================================== + Self Consistent Field (SCF#4) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6157721676E+00 3.396E-03 1.289 +2 -2.6158309106E+00 3.300E-03 1.283 +3 -2.6158338481E+00 1.169E-02 1.301 +4 -2.6158314175E+00 4.750E-03 1.265 +5 -2.6158310097E+00 1.803E-04 1.254 +6 -2.6158310093E+00 5.614E-05 1.243 +7 -2.6158310092E+00 3.843E-05 1.240 +8 -2.6158310109E+00 2.120E-05 1.235 +9 -2.6158310110E+00 1.077E-05 1.229 +10 -2.6158310111E+00 4.423E-06 1.227 +11 -2.6158310135E+00 1.727E-06 1.216 +12 -2.6158310110E+00 9.199E-07 1.203 +Total number of SCF: 12 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6158310110E+00 (Ha/atom) +Total free energy : -5.2316620221E+01 (Ha) +Band structure energy : -9.0976537835E+00 (Ha) +Exchange correlation energy : -2.0465909205E+01 (Ha) +Self and correction energy : -7.6945216372E+01 (Ha) +-Entropy*kb*T : -1.4349348641E-01 (Ha) +Fermi level : -2.8425013803E-02 (Ha) +RMS force : 1.0855473645E-02 (Ha/Bohr) +Maximum force : 1.4071158391E-02 (Ha/Bohr) +Time for force calculation : 0.046 (sec) +Pressure : -5.4256467175E+00 (GPa) +Maximum stress : 5.8135811834E+00 (GPa) +Time for stress calculation : 0.118 (sec) +MD step time : 15.516 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.893719321631 18.8932552651579 18.8928212274633 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248602 (Bohr) +Mesh spacing in y-direction : 0.248595 (Bohr) +Mesh spacing in z direction : 0.24859 (Bohr) +=================================================================== + Self Consistent Field (SCF#5) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6158510941E+00 3.347E-03 1.298 +2 -2.6159091391E+00 1.521E-03 1.275 +3 -2.6159121847E+00 1.267E-02 1.283 +4 -2.6159094482E+00 6.906E-04 1.251 +5 -2.6159094542E+00 8.059E-04 1.248 +6 -2.6159094425E+00 6.295E-05 1.241 +7 -2.6159094394E+00 2.282E-05 1.232 +8 -2.6159094416E+00 1.331E-05 1.233 +9 -2.6159094416E+00 8.250E-06 1.228 +10 -2.6159094421E+00 4.597E-06 1.225 +11 -2.6159094415E+00 1.981E-06 1.211 +12 -2.6159094397E+00 2.124E-06 1.182 +13 -2.6159094417E+00 1.972E-06 1.176 +14 -2.6159094403E+00 7.433E-07 1.175 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6159094403E+00 (Ha/atom) +Total free energy : -5.2318188806E+01 (Ha) +Band structure energy : -9.0985790875E+00 (Ha) +Exchange correlation energy : -2.0468592268E+01 (Ha) +Self and correction energy : -7.6945216770E+01 (Ha) +-Entropy*kb*T : -1.4318523051E-01 (Ha) +Fermi level : -2.8469416111E-02 (Ha) +RMS force : 1.1016358567E-02 (Ha/Bohr) +Maximum force : 1.4397243663E-02 (Ha/Bohr) +Time for force calculation : 0.046 (sec) +Pressure : -5.4220326813E+00 (GPa) +Maximum stress : 5.8174571383E+00 (GPa) +Time for stress calculation : 0.118 (sec) +MD step time : 17.790 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8919395295415 18.8912379590423 18.8905844576911 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248578 (Bohr) +Mesh spacing in y-direction : 0.248569 (Bohr) +Mesh spacing in z direction : 0.24856 (Bohr) +=================================================================== + Self Consistent Field (SCF#6) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6159487287E+00 3.372E-03 1.291 +2 -2.6160078610E+00 1.731E-03 1.280 +3 -2.6160110635E+00 1.270E-02 1.286 +4 -2.6160082368E+00 1.946E-03 1.259 +5 -2.6160081596E+00 3.646E-04 1.251 +6 -2.6160081583E+00 6.474E-05 1.243 +7 -2.6160081573E+00 3.687E-05 1.240 +8 -2.6160081588E+00 2.281E-05 1.236 +9 -2.6160081590E+00 1.236E-05 1.233 +10 -2.6160081593E+00 5.492E-06 1.225 +11 -2.6160081610E+00 2.002E-06 1.211 +12 -2.6160081590E+00 1.579E-06 1.181 +13 -2.6160081610E+00 1.361E-06 1.204 +14 -2.6160081620E+00 5.044E-07 1.176 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6160081620E+00 (Ha/atom) +Total free energy : -5.2320163240E+01 (Ha) +Band structure energy : -9.0995684685E+00 (Ha) +Exchange correlation energy : -2.0472011587E+01 (Ha) +Self and correction energy : -7.6945217135E+01 (Ha) +-Entropy*kb*T : -1.4280802491E-01 (Ha) +Fermi level : -2.8519371062E-02 (Ha) +RMS force : 1.1212537982E-02 (Ha/Bohr) +Maximum force : 1.4746055461E-02 (Ha/Bohr) +Time for force calculation : 0.046 (sec) +Pressure : -5.4174402490E+00 (GPa) +Maximum stress : 5.8214008667E+00 (GPa) +Time for stress calculation : 0.118 (sec) +MD step time : 17.865 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8897919558768 18.8888013159287 18.8878817173803 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.24855 (Bohr) +Mesh spacing in y-direction : 0.248537 (Bohr) +Mesh spacing in z direction : 0.248525 (Bohr) +=================================================================== + Self Consistent Field (SCF#7) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6160689582E+00 3.385E-03 1.290 +2 -2.6161280214E+00 2.444E-03 1.288 +3 -2.6161310614E+00 1.147E-02 1.297 +4 -2.6161284527E+00 3.424E-03 1.262 +5 -2.6161282444E+00 3.251E-04 1.247 +6 -2.6161282437E+00 5.425E-05 1.389 +7 -2.6161282428E+00 3.265E-05 1.236 +8 -2.6161282449E+00 1.817E-05 1.237 +9 -2.6161282444E+00 9.636E-06 1.233 +10 -2.6161282447E+00 4.414E-06 1.234 +11 -2.6161282461E+00 1.703E-06 1.211 +12 -2.6161282441E+00 8.534E-07 1.199 +Total number of SCF: 12 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6161282441E+00 (Ha/atom) +Total free energy : -5.2322564882E+01 (Ha) +Band structure energy : -9.1006520070E+00 (Ha) +Exchange correlation energy : -2.0476166717E+01 (Ha) +Self and correction energy : -7.6945217002E+01 (Ha) +-Entropy*kb*T : -1.4236067806E-01 (Ha) +Fermi level : -2.8574811077E-02 (Ha) +RMS force : 1.1432621731E-02 (Ha/Bohr) +Maximum force : 1.5110771275E-02 (Ha/Bohr) +Time for force calculation : 0.046 (sec) +Pressure : -5.4119115384E+00 (GPa) +Maximum stress : 5.8254250751E+00 (GPa) +Time for stress calculation : 0.118 (sec) +MD step time : 15.650 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8872706381413 18.8859377782233 18.8847039060953 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248517 (Bohr) +Mesh spacing in y-direction : 0.248499 (Bohr) +Mesh spacing in z direction : 0.248483 (Bohr) +=================================================================== + Self Consistent Field (SCF#8) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6162086571E+00 3.454E-03 1.307 +2 -2.6162693431E+00 7.728E-03 1.275 +3 -2.6162702635E+00 1.019E-02 1.277 +4 -2.6162696427E+00 6.843E-03 1.282 +5 -2.6162685934E+00 1.597E-04 1.246 +6 -2.6162685975E+00 5.499E-05 1.257 +7 -2.6162685981E+00 3.748E-05 1.241 +8 -2.6162685995E+00 2.065E-05 1.236 +9 -2.6162685994E+00 1.085E-05 1.232 +10 -2.6162685998E+00 5.479E-06 1.230 +11 -2.6162686012E+00 2.143E-06 1.211 +12 -2.6162685996E+00 1.281E-06 1.188 +13 -2.6162686006E+00 1.377E-06 1.162 +14 -2.6162686028E+00 8.843E-07 1.175 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6162686028E+00 (Ha/atom) +Total free energy : -5.2325372057E+01 (Ha) +Band structure energy : -9.1017937746E+00 (Ha) +Exchange correlation energy : -2.0481065299E+01 (Ha) +Self and correction energy : -7.6945217081E+01 (Ha) +-Entropy*kb*T : -1.4184115976E-01 (Ha) +Fermi level : -2.8634473655E-02 (Ha) +RMS force : 1.1669031628E-02 (Ha/Bohr) +Maximum force : 1.5575163880E-02 (Ha/Bohr) +Time for force calculation : 0.046 (sec) +Pressure : -5.4054413199E+00 (GPa) +Maximum stress : 5.8295072331E+00 (GPa) +Time for stress calculation : 0.117 (sec) +MD step time : 17.853 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8843701178566 18.8826403564957 18.8810423350812 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248479 (Bohr) +Mesh spacing in y-direction : 0.248456 (Bohr) +Mesh spacing in z direction : 0.248435 (Bohr) +=================================================================== + Self Consistent Field (SCF#9) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6163686745E+00 3.385E-03 1.300 +2 -2.6164280137E+00 3.001E-03 1.280 +3 -2.6164319865E+00 1.461E-02 1.292 +4 -2.6164284354E+00 3.157E-03 1.264 +5 -2.6164282265E+00 4.500E-04 1.246 +6 -2.6164282205E+00 7.113E-05 1.240 +7 -2.6164282212E+00 3.410E-05 1.235 +8 -2.6164282234E+00 1.972E-05 1.235 +9 -2.6164282231E+00 1.125E-05 1.231 +10 -2.6164282233E+00 6.470E-06 1.225 +11 -2.6164282242E+00 2.318E-06 1.207 +12 -2.6164282225E+00 1.607E-06 1.186 +13 -2.6164282246E+00 2.685E-06 1.179 +14 -2.6164282235E+00 8.587E-07 1.160 +Total number of SCF: 14 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6164282235E+00 (Ha/atom) +Total free energy : -5.2328564470E+01 (Ha) +Band structure energy : -9.1030008285E+00 (Ha) +Exchange correlation energy : -2.0486705429E+01 (Ha) +Self and correction energy : -7.6945217438E+01 (Ha) +-Entropy*kb*T : -1.4124821506E-01 (Ha) +Fermi level : -2.8697681588E-02 (Ha) +RMS force : 1.1916655984E-02 (Ha/Bohr) +Maximum force : 1.6320810261E-02 (Ha/Bohr) +Time for force calculation : 0.046 (sec) +Pressure : -5.3979777667E+00 (GPa) +Maximum stress : 5.8336129525E+00 (GPa) +Time for stress calculation : 0.117 (sec) +MD step time : 17.825 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8810843527925 18.8789013916923 18.876887339682 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248435 (Bohr) +Mesh spacing in y-direction : 0.248407 (Bohr) +Mesh spacing in z direction : 0.24838 (Bohr) +=================================================================== + Self Consistent Field (SCF#10) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6165480653E+00 3.424E-03 1.297 +2 -2.6166084419E+00 4.518E-03 1.283 +3 -2.6166115485E+00 1.327E-02 1.278 +4 -2.6166090089E+00 5.148E-03 1.272 +5 -2.6166084274E+00 2.003E-04 1.246 +6 -2.6166084298E+00 5.506E-05 1.257 +7 -2.6166084307E+00 3.573E-05 1.234 +8 -2.6166084322E+00 1.750E-05 1.236 +9 -2.6166084319E+00 9.534E-06 1.228 +10 -2.6166084323E+00 4.972E-06 1.225 +11 -2.6166084327E+00 2.320E-06 1.209 +12 -2.6166084309E+00 1.114E-06 1.189 +13 -2.6166084327E+00 8.660E-07 1.177 +Total number of SCF: 13 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6166084327E+00 (Ha/atom) +Total free energy : -5.2332168653E+01 (Ha) +Band structure energy : -9.1042773163E+00 (Ha) +Exchange correlation energy : -2.0493097428E+01 (Ha) +Self and correction energy : -7.6945218072E+01 (Ha) +-Entropy*kb*T : -1.4058245138E-01 (Ha) +Fermi level : -2.8764439380E-02 (Ha) +RMS force : 1.2171731436E-02 (Ha/Bohr) +Maximum force : 1.7112369646E-02 (Ha/Bohr) +Time for force calculation : 0.046 (sec) +Pressure : -5.3895638381E+00 (GPa) +Maximum stress : 5.8378199911E+00 (GPa) +Time for stress calculation : 0.118 (sec) +MD step time : 16.662 (sec) +*************************************************************************** + Reinitialized parameters +*************************************************************************** +LATVEC_SCALE: 18.8774048711676 18.8747104701288 18.8722259615035 +CHEB_DEGREE: 30 +*************************************************************************** + Reinitialization +*************************************************************************** +Mesh spacing in x-direction : 0.248387 (Bohr) +Mesh spacing in y-direction : 0.248351 (Bohr) +Mesh spacing in z direction : 0.248319 (Bohr) +=================================================================== + Self Consistent Field (SCF#11) +=================================================================== +Iteration Free Energy (Ha/atom) SCF Error Timing (sec) +1 -2.6167532989E+00 3.373E-03 1.340 +2 -2.6168124483E+00 1.535E-03 1.269 +3 -2.6168154404E+00 1.235E-02 1.282 +4 -2.6168128030E+00 5.485E-04 1.253 +5 -2.6168128293E+00 1.093E-03 1.249 +6 -2.6168127988E+00 6.755E-05 1.245 +7 -2.6168127981E+00 3.298E-05 1.232 +8 -2.6168128001E+00 2.095E-05 1.236 +9 -2.6168127993E+00 1.187E-05 1.234 +10 -2.6168127996E+00 6.001E-06 1.225 +11 -2.6168128007E+00 2.099E-06 1.211 +12 -2.6168127989E+00 8.068E-07 1.212 +Total number of SCF: 12 +==================================================================== + Energy and force calculation +==================================================================== +Free energy per atom : -2.6168127989E+00 (Ha/atom) +Total free energy : -5.2336255979E+01 (Ha) +Band structure energy : -9.1056148551E+00 (Ha) +Exchange correlation energy : -2.0500267743E+01 (Ha) +Self and correction energy : -7.6945219214E+01 (Ha) +-Entropy*kb*T : -1.3984101949E-01 (Ha) +Fermi level : -2.8834521210E-02 (Ha) +RMS force : 1.2431612587E-02 (Ha/Bohr) +Maximum force : 1.7951609070E-02 (Ha/Bohr) +Time for force calculation : 0.047 (sec) +Pressure : -5.3802912455E+00 (GPa) +Maximum stress : 5.8422471202E+00 (GPa) +Time for stress calculation : 0.120 (sec) +*************************************************************************** + Timing info +*************************************************************************** +Total walltime : 219.244 sec +___________________________________________________________________________ + +*************************************************************************** +* Material Physics & Mechanics Group, Georgia Tech * +* PI: Phanish Suryanarayana * +* List of contributors: See the documentation * +* Citation: See README.md or the documentation for details * +* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * +* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * +*************************************************************************** + diff --git a/tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.refaimd b/tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.refaimd deleted file mode 100644 index 2551e57c..00000000 --- a/tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.refaimd +++ /dev/null @@ -1,939 +0,0 @@ -:Description: - -:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr -:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu - where atu is the atomic unit of time, hbar/Ha -:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr -:Desc_MDTM: MD time. Unit=second -:Desc_TEL: Electronic temperature. Unit=Kelvin -:Desc_TIO: Ionic temperature. Unit=Kelvin -:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom -:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom -:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom - where N = number of particles, k = Boltzmann constant -:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom -:Desc_UEN: Internal energy. Unit=Ha/atom -:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom -:Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 -:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom -:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa -:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa -:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa - where N = number of particles, k = Boltzmann constant, V = volume -:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr - - -:MDSTEP: 1 -:MDTM: 22.50 -:TWIST: 0 -:TEL: 2400 -:TIO: 2400 -:TEN: -2.6302760701E+00 -:KEN: 1.0830495547E-02 -:KENIG: 1.1400521628E-02 -:FEN: -2.6411065657E+00 -:UEN: -2.6366295790E+00 -:TSEN: -4.4769866837E-03 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 - 0.0000000000E+00 0.0000000000E+00 4.3400663469E+00 - 0.0000000000E+00 0.0000000000E+00 8.6801326939E+00 - 0.0000000000E+00 5.8266493047E+00 0.0000000000E+00 - 0.0000000000E+00 5.8266493047E+00 4.3400663469E+00 - 0.0000000000E+00 5.8266493047E+00 8.6801326939E+00 - 0.0000000000E+00 1.1653298609E+01 0.0000000000E+00 - 0.0000000000E+00 1.1653298609E+01 4.3400663469E+00 - 0.0000000000E+00 1.1653298609E+01 8.6801326939E+00 - 4.4408516321E+00 0.0000000000E+00 0.0000000000E+00 - 4.4408516321E+00 0.0000000000E+00 4.3400663469E+00 - 4.4408516321E+00 0.0000000000E+00 8.6801326939E+00 - 4.4408516321E+00 5.8266493047E+00 0.0000000000E+00 - 4.4408516321E+00 5.8266493047E+00 4.3400663469E+00 - 4.4408516321E+00 5.8266493047E+00 8.6801326939E+00 - 4.4408516321E+00 1.1653298609E+01 0.0000000000E+00 - 4.4408516321E+00 1.1653298609E+01 4.3400663469E+00 - 4.4408516321E+00 1.1653298609E+01 8.6801326939E+00 - 8.8817032643E+00 0.0000000000E+00 0.0000000000E+00 - 8.8817032643E+00 0.0000000000E+00 4.3400663469E+00 -:V: - -5.4115960593E-06 6.8757504739E-04 4.3922438152E-04 - 3.8694989004E-05 -1.5727041676E-04 5.1733352092E-04 - 6.4493512096E-04 -4.5410623326E-04 -3.0784978494E-04 - -3.2920353408E-04 -1.3619507306E-04 -4.4905699411E-04 - 2.8658596847E-04 4.0521884520E-04 -3.3919761855E-05 - -1.7257170604E-04 3.6971498788E-04 -5.9862979356E-05 - -7.9421449907E-04 -5.9309718414E-04 2.6589589603E-04 - 4.2828044862E-05 1.3096756605E-04 3.9314269459E-04 - 4.5465738595E-04 -4.7430305976E-04 1.4680556482E-04 - -4.4755494676E-04 -2.7196430316E-05 -6.1824709024E-04 - 1.9833970038E-05 1.9314745507E-05 -3.0782221035E-04 - 9.7647151403E-05 -4.7512767927E-04 4.3477905793E-04 - 5.4955924937E-04 -4.6798769662E-05 3.8047920243E-04 - 7.8609552254E-04 3.4903251115E-04 -5.0995713773E-05 - -6.9672186847E-04 5.7127171699E-04 -2.9842613860E-04 - 6.0936489813E-05 -8.3800668387E-04 -5.9302851573E-05 - -3.2116552146E-04 5.9649571820E-04 -2.8067877708E-05 - -1.4190760424E-04 9.6824119483E-06 -4.3002551677E-04 - 1.9870593859E-04 1.8287976962E-04 2.8359561204E-04 - -3.6274411453E-04 -4.1742848824E-05 -1.3552040525E-04 -:F: - -8.4344291940E-02 -1.4029342453E-08 -4.3140080588E-04 - -8.4344345514E-02 -1.8257088655E-08 4.2991815163E-04 - -5.2802732711E-02 -3.3831889065E-08 1.4779980264E-06 - -5.2899768247E-02 1.4882663443E-04 -1.1951807147E-03 - -5.2899954476E-02 1.4874459336E-04 1.1937531892E-03 - -5.0287594094E-02 -1.5717517431E-03 1.3973709266E-06 - -5.2899819093E-02 -1.4882874636E-04 -1.1951044979E-03 - -5.2899943917E-02 -1.4870100257E-04 1.1937197298E-03 - -5.0287650892E-02 1.5717805223E-03 1.3642338649E-06 - 8.4345364845E-02 -2.6476157499E-08 -4.3166655915E-04 - 8.4345407278E-02 -2.1281850694E-08 4.3028881947E-04 - 5.2802969939E-02 -1.3989446690E-08 1.4264057432E-06 - 5.2899894075E-02 1.4904439762E-04 -1.1952651725E-03 - 5.2899996230E-02 1.4893625983E-04 1.1939195910E-03 - 5.0287647440E-02 -1.5714939448E-03 1.3702011343E-06 - 5.2899878645E-02 -1.4897964753E-04 -1.1952153216E-03 - 5.2900084614E-02 -1.4891154118E-04 1.1938788100E-03 - 5.0287744047E-02 1.5715273045E-03 1.3517740503E-06 - -1.4677014040E-06 -6.8303091901E-09 3.8025276221E-02 - -1.4185277829E-06 -5.8390325554E-08 -3.8025309424E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020212061E+01 -:STRIO: - -1.5729135264E+00 1.6646213304E-01 -3.0701669489E-01 - 1.6646213304E-01 -1.6073820576E+00 6.5632546225E-02 - -3.0701669489E-01 6.5632546225E-02 -1.0232852406E+00 -:STRESS: - -1.1328763012E+01 1.3902290150E-07 -1.9365647584E-06 - 1.3902290150E-07 1.8309392875E+00 -3.7891280137E-07 - -1.9365647584E-06 -3.7891280137E-07 -2.2161420625E+01 -:PRESIO: 1.4011936082E+00 -:PRES: 1.0553081450E+01 -:PRESIG: 1.4749406402E+00 -:MIND: -Al - Al: 4.3400663469E+00 -C - C: 4.3400663469E+00 -Al - C: 4.4408516321E+00 -:MDSTEP: 2 -:MDTM: 19.18 -:TWIST: 0 -:TEL: 2400 -:TIO: 2409.02771709026 -:TEN: -2.6303237553E+00 -:KEN: 1.0871234984E-02 -:KENIG: 1.1443405247E-02 -:FEN: -2.6411949903E+00 -:UEN: -2.6367154444E+00 -:TSEN: -4.4795459238E-03 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 1.3319413667E+01 2.8424801529E-02 1.8142832601E-02 - 1.3321237060E+01 1.7473463732E+01 4.3614686505E+00 - 2.4827226495E-02 1.7461192344E+01 8.6674069510E+00 - 1.3307120545E+01 5.8210240828E+00 1.3001607596E+01 - 1.0009459925E-02 5.8434064853E+00 4.3387060215E+00 - 1.3313686576E+01 5.8418789481E+00 8.6776588849E+00 - 1.3287896686E+01 1.1628774412E+01 1.0950782165E-02 - 1.3322500567E+01 1.1658707727E+01 4.3563610615E+00 - 1.7048415713E-02 1.1633745228E+01 8.6862026965E+00 - 4.4252802887E+00 1.7478841075E+01 1.2994639698E+01 - 4.4446024535E+00 7.9848346830E-04 4.3273561860E+00 - 4.4467232506E+00 1.7460323305E+01 8.6981077112E+00 - 4.4654089601E+00 5.8247197920E+00 1.5687725386E-02 - 4.4751875279E+00 5.8410837122E+00 4.3380000962E+00 - 4.4137961123E+00 5.8502114440E+00 8.6677965270E+00 - 4.4452089752E+00 1.1618649688E+01 1.3017720286E+01 - 4.4294126354E+00 1.1677952958E+01 4.3389479466E+00 - 4.4367325001E+00 1.1653753495E+01 8.6623561220E+00 - 8.8899177831E+00 7.5603687154E-03 1.4692242984E-02 - 8.8667070747E+00 1.7478239713E+01 4.3314960858E+00 -:V: - -7.6303642574E-05 6.8755110246E-04 4.3884649622E-04 - -3.2198637804E-05 -1.5726495783E-04 5.1767686414E-04 - 6.0053143836E-04 -4.5409045515E-04 -3.0783782703E-04 - -3.7365486818E-04 -1.3606524208E-04 -4.5004592486E-04 - 2.4211304342E-04 4.0532976167E-04 -3.2915219483E-05 - -2.1483293325E-04 3.6838104551E-04 -5.9859721139E-05 - -8.3864968979E-04 -5.9320163167E-04 2.6488214324E-04 - -1.6363865806E-06 1.3083802262E-04 3.9413234364E-04 - 4.1237427839E-04 -4.7296545270E-04 1.4680160146E-04 - -3.7664623159E-04 -2.7195505915E-05 -6.1858839040E-04 - 9.0726451991E-05 1.9314055311E-05 -3.0744983354E-04 - 1.4202518557E-04 -4.7511115277E-04 4.3476512303E-04 - 5.9400301908E-04 -4.6671867357E-05 3.7946132617E-04 - 8.3053114475E-04 3.4914554446E-04 -4.9990437158E-05 - -6.5443033802E-04 5.6993097551E-04 -2.9841459931E-04 - 1.0539725455E-04 -8.3810273341E-04 -6.0305377987E-05 - -2.7669128339E-04 5.9634979369E-04 -2.7063433443E-05 - -9.9635304580E-05 1.1002959599E-05 -4.3000941225E-04 - 1.9869625083E-04 1.8287339104E-04 3.5538217747E-04 - -3.6273416648E-04 -4.1741506086E-05 -2.0731218758E-04 -:F: - -8.5903151496E-02 2.1170218111E-03 -2.8340827815E-03 - -8.4398995505E-02 -7.8941028509E-04 -3.1127592467E-03 - -5.3685813610E-02 -9.8953430968E-04 7.2841373808E-03 - -4.9627323412E-02 -7.0138103356E-04 2.3098382077E-03 - -5.0125004319E-02 2.7943939054E-04 -7.7998164116E-04 - -5.2078972967E-02 -1.1227754126E-03 -2.0165007761E-03 - -5.0480738477E-02 -6.0187927934E-04 -6.6816610902E-04 - -5.3730421184E-02 9.9163947853E-04 -4.7579797438E-04 - -5.1172781752E-02 8.9620719762E-04 2.1366938895E-03 - 8.4579411156E-02 8.8913386964E-05 4.9880322683E-03 - 8.4244876335E-02 4.0475519025E-04 1.8214643352E-03 - 5.5211969834E-02 -9.1060460617E-04 -8.1512695650E-03 - 4.9635245608E-02 -6.4911575198E-04 -5.6469963566E-03 - 5.1765134801E-02 8.8034516855E-05 2.2116806205E-03 - 5.0311447022E-02 -8.3147910813E-04 3.9130697851E-03 - 4.9766500967E-02 -1.6636097356E-03 -2.8478208265E-03 - 5.3738799262E-02 1.5077017877E-03 -1.4752186924E-03 - 5.2029411472E-02 1.9207452639E-03 3.3646716424E-03 - 5.7156672336E-04 -3.1796417763E-04 3.9350931695E-02 - -6.5116045960E-04 2.8329567619E-04 -3.9371925855E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020213437E+01 -:STRIO: - -1.5749822761E+00 1.6500668283E-01 -2.5326398050E-01 - 1.6500668283E-01 -1.6056534590E+00 6.0852819455E-02 - -2.5326398050E-01 6.0852819455E-02 -1.0384628857E+00 -:STRESS: - -1.1241494107E+01 -1.8928162382E-02 7.6788094843E-02 - -1.8928162382E-02 1.8294440547E+00 -3.7552084303E-02 - 7.6788094843E-02 -3.7552084303E-02 -2.2153849121E+01 -:PRESIO: 1.4063662069E+00 -:PRES: 1.0521966391E+01 -:PRESIG: 1.4804885449E+00 -:MIND: -Al - Al: 4.2966253995E+00 -C - C: 1.7996109882E+01 -Al - C: 4.4295463666E+00 -:MDSTEP: 3 -:MDTM: 18.87 -:TWIST: 0 -:TEL: 2400 -:TIO: 2438.14745283639 -:TEN: -2.6303741984E+00 -:KEN: 1.1002643805E-02 -:KENIG: 1.1581730321E-02 -:FEN: -2.6413768422E+00 -:UEN: -2.6368971344E+00 -:TSEN: -4.4797078004E-03 -:NPT_NP_HAMIL: -4.7683254074E-05 -:R: - 1.3313275239E+01 5.6917460613E-02 3.6183571338E-02 - 1.3316973919E+01 1.7466935945E+01 4.3827589849E+00 - 4.7784290049E-02 1.7442388676E+01 8.6549377426E+00 - 1.3289951778E+01 5.8153756198E+00 1.2983088481E+01 - 1.8275437037E-02 5.8601700180E+00 4.3373193283E+00 - 1.3302997348E+01 5.8570665327E+00 8.6751164298E+00 - 1.3251478260E+01 1.1604234217E+01 2.1876159305E-02 - 1.3320566189E+01 1.1664150214E+01 4.3726364439E+00 - 3.2315536093E-02 1.1614226899E+01 8.6923466366E+00 - 4.4126505811E+00 1.7477720070E+01 1.2969247126E+01 - 4.4512794180E+00 1.6108692877E-03 4.3147123095E+00 - 4.4545119057E+00 1.7440653513E+01 8.7157968523E+00 - 4.4916858316E+00 5.8227681138E+00 3.1176119940E-02 - 4.5113150066E+00 5.8555182871E+00 4.3360115575E+00 - 4.3884939672E+00 5.8737399760E+00 8.6555996966E+00 - 4.4512944681E+00 1.1583949909E+01 1.3015131445E+01 - 4.4198429608E+00 1.1702654750E+01 4.3377789756E+00 - 4.4344218353E+00 1.1654275021E+01 8.6447009223E+00 - 8.8981752652E+00 1.5094407229E-02 3.2452732151E-02 - 8.8516630683E+00 1.7476536487E+01 4.3198551738E+00 -:V: - -1.4845430387E-04 6.8907838680E-04 4.3630467998E-04 - -1.0310159270E-04 -1.5787071832E-04 5.1487205902E-04 - 5.5520322877E-04 -4.5475578797E-04 -3.0160485546E-04 - -4.1521664890E-04 -1.3660479240E-04 -4.4794049894E-04 - 1.9990784843E-04 4.0541628663E-04 -3.3558544651E-05 - -2.5851276507E-04 3.6730290056E-04 -6.1532152946E-05 - -8.8075844279E-04 -5.9349035771E-04 2.6422383528E-04 - -4.6781804900E-05 1.3162336947E-04 3.9358839002E-04 - 3.6922642605E-04 -4.7203942080E-04 1.4854322017E-04 - -3.0544213092E-04 -2.7110849975E-05 -6.1417100770E-04 - 1.6147850166E-04 1.9647078507E-05 -3.0580691636E-04 - 1.8836409442E-04 -4.7570247700E-04 4.2775712950E-04 - 6.3549085330E-04 -4.7200202665E-05 3.7457773306E-04 - 8.7372205833E-04 3.4909179702E-04 -4.8113826006E-05 - -6.1191766294E-04 5.6902386040E-04 -2.9501755347E-04 - 1.4717410488E-04 -8.3919397490E-04 -6.2676148445E-05 - -2.3143701374E-04 5.9739846916E-04 -2.8293059572E-05 - -5.5882083964E-05 1.2612806286E-05 -4.2702501089E-04 - 1.9970239971E-04 1.8220633918E-04 4.2952702476E-04 - -3.6383054367E-04 -4.1191516799E-05 -2.8155082508E-04 -:F: - -8.6845324248E-02 4.1812454579E-03 -5.1317803382E-03 - -8.4042390110E-02 -1.5431474934E-03 -6.8005061896E-03 - -5.4167453985E-02 -1.9333077605E-03 1.4563445013E-02 - -4.6311673762E-02 -1.5402613925E-03 5.8761105530E-03 - -4.7198393518E-02 3.7603278172E-04 -2.7179274402E-03 - -5.3577142440E-02 -6.9323099986E-04 -4.0495575261E-03 - -4.8017530743E-02 -1.0855344825E-03 -1.8121408735E-04 - -5.4257221614E-02 2.1462827695E-03 -2.1412402511E-03 - -5.1756499262E-02 1.9573925016E-04 4.3230521246E-03 - 8.4205803999E-02 2.2797769682E-04 1.0586363400E-02 - 8.3643552201E-02 7.7831638808E-04 3.1228344410E-03 - 5.7270947582E-02 -1.8614100561E-03 -1.6373305382E-02 - 4.6271393494E-02 -1.4324445579E-03 -1.0110102736E-02 - 5.0484998164E-02 1.6386360396E-05 3.3404438911E-03 - 5.0081897981E-02 -1.1477427151E-04 7.6165747915E-03 - 4.6620182365E-02 -3.0782292744E-03 -4.3219667409E-03 - 5.4242126663E-02 3.1955572514E-03 -4.2660165835E-03 - 5.3479780116E-02 2.2355428711E-03 6.6913306711E-03 - 1.1221906943E-03 -6.3707250741E-04 4.0932136989E-02 - -1.2492435770E-03 5.6633196906E-04 -4.0958674599E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020216189E+01 -:STRIO: - -1.6159034525E+00 1.6433800385E-01 -1.9752351525E-01 - 1.6433800385E-01 -1.6078182886E+00 5.6553502336E-02 - -1.9752351525E-01 5.6553502336E-02 -1.0435490537E+00 -:STRESS: - -1.1052399119E+01 -3.8923464032E-02 1.5629229643E-01 - -3.8923464032E-02 1.8119912287E+00 -7.7223085443E-02 - 1.5629229643E-01 -7.7223085443E-02 -2.2159549245E+01 -:PRESIO: 1.4224235983E+00 -:PRES: 1.0466652378E+01 -:PRESIG: 1.4983840104E+00 -:MIND: -Al - Al: 4.2538177595E+00 -C - C: 1.7980154132E+01 -Al - C: 4.4152996349E+00 -:MDSTEP: 4 -:MDTM: 13.64 -:TWIST: 0 -:TEL: 2400 -:TIO: 2486.2377315978 -:TEN: -2.6304312567E+00 -:KEN: 1.1219661117E-02 -:KENIG: 1.1810169597E-02 -:FEN: -2.6416509178E+00 -:UEN: -2.6371740090E+00 -:TSEN: -4.4769088183E-03 -:NPT_NP_HAMIL: -9.7472967385E-05 -:R: - 1.3304126021E+01 8.5531813539E-02 5.4031223664E-02 - 1.3309795776E+01 1.7460359956E+01 4.4037960645E+00 - 6.8841354458E-02 1.7423533383E+01 8.6429854787E+00 - 1.3271188922E+01 5.8096783287E+00 1.2964790076E+01 - 2.4895548263E-02 5.8769327787E+00 4.3358398546E+00 - 1.3290456379E+01 5.8722175136E+00 8.6724363647E+00 - 1.3213422388E+01 1.1579676570E+01 3.2786234385E-02 - 1.3316749231E+01 1.1669662743E+01 4.3888245080E+00 - 4.5772726320E-02 1.1594731471E+01 8.6986365574E+00 - 4.4029554863E+00 1.7476607907E+01 1.2944244505E+01 - 4.4608555415E+00 2.4496132572E-03 4.3021877658E+00 - 4.4642829682E+00 1.7420935308E+01 8.7329037369E+00 - 4.5195478786E+00 5.8207683016E+00 4.6300651863E-02 - 4.5491658585E+00 5.8699415221E+00 4.3341411219E+00 - 4.3649518779E+00 5.8972451106E+00 8.6436783439E+00 - 4.4589939071E+00 1.1549171861E+01 1.3012396034E+01 - 4.4121648336E+00 1.1727447133E+01 4.3364632846E+00 - 4.4339702552E+00 1.1654873750E+01 8.6272935707E+00 - 8.9065134769E+00 2.2572531799E-02 5.3391700885E-02 - 8.8365340199E+00 1.7474878847E+01 4.3050291266E+00 -:V: - -2.2116678613E-04 6.9170330766E-04 4.3143635774E-04 - -1.7351937635E-04 -1.5896335618E-04 5.0850199489E-04 - 5.0901871308E-04 -4.5579462431E-04 -2.8899204098E-04 - -4.5356012517E-04 -1.3772232190E-04 -4.4243239610E-04 - 1.6002992778E-04 4.0521122588E-04 -3.5797032228E-05 - -3.0315658410E-04 3.6624918946E-04 -6.4852560584E-05 - -9.1993596583E-04 -5.9363932886E-04 2.6373233871E-04 - -9.2268474744E-05 1.3325602781E-04 3.9128537171E-04 - 3.2530468246E-04 -4.7126880826E-04 1.5198145670E-04 - -2.3436242577E-04 -2.6884650117E-05 -6.0449532691E-04 - 2.3148649639E-04 2.0275208722E-05 -3.0279263753E-04 - 2.3619881486E-04 -4.7665405373E-04 4.1346297734E-04 - 6.7351759110E-04 -4.8342057385E-05 3.6560959258E-04 - 9.1497995881E-04 3.4865717190E-04 -4.5247859181E-05 - -5.6908996213E-04 5.6819664586E-04 -2.8824481827E-04 - 1.8612084118E-04 -8.4070014639E-04 -6.6223763302E-05 - -1.8560566543E-04 5.9931369997E-04 -3.1837868879E-05 - -1.0916181372E-05 1.4473254545E-05 -4.2085942781E-04 - 2.0156208514E-04 1.8077094083E-04 5.0616370206E-04 - -3.6571901130E-04 -4.0070640831E-05 -3.5842760979E-04 -:F: - -8.7143383856E-02 6.1726757356E-03 -7.3270477992E-03 - -8.3309294392E-02 -2.2476949863E-03 -1.0593734140E-02 - -5.4204234529E-02 -2.8322501189E-03 2.1754395193E-02 - -4.3023510569E-02 -2.3684585997E-03 9.4545373659E-03 - -4.4165637151E-02 4.4439828370E-04 -4.6025124159E-03 - -5.4755547421E-02 -2.8760557176E-04 -6.0738330266E-03 - -4.5572842499E-02 -1.5917334576E-03 2.6763863870E-04 - -5.4462091781E-02 3.3082971452E-03 -3.7784155254E-03 - -5.2003580003E-02 -5.1988256029E-04 6.5198222247E-03 - 8.3200173094E-02 4.2713747978E-04 1.6326630642E-02 - 8.2554117395E-02 1.1278770640E-03 4.3523288504E-03 - 5.8942160805E-02 -2.8514119564E-03 -2.4600090226E-02 - 4.2882459571E-02 -2.2015832791E-03 -1.4525930936E-02 - 4.9100702726E-02 -6.0479076060E-05 4.5684478463E-03 - 4.9574129128E-02 5.7136028430E-04 1.1070474720E-02 - 4.3523502109E-02 -4.3874813324E-03 -5.6034465803E-03 - 5.4395010109E-02 4.8951931544E-03 -7.1358850956E-03 - 5.4602830521E-02 2.5109203692E-03 9.9428615835E-03 - 1.6120750661E-03 -9.5748255476E-04 4.2795926780E-02 - -1.7470383218E-03 8.4820397705E-04 -4.2812168100E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020220320E+01 -:STRIO: - -1.6931489247E+00 1.6428080127E-01 -1.4060987897E-01 - 1.6428080127E-01 -1.6118984852E+00 5.2794667818E-02 - -1.4060987897E-01 5.2794667818E-02 -1.0383961971E+00 -:STRESS: - -1.0765161527E+01 -5.9855481277E-02 2.3475491524E-01 - -5.9855481277E-02 1.7795872404E+00 -1.1798496347E-01 - 2.3475491524E-01 -1.1798496347E-01 -2.2176534672E+01 -:PRESIO: 1.4478145357E+00 -:PRES: 1.0387369653E+01 -:PRESIG: 1.5279378106E+00 -:MIND: -Al - Al: 4.2121552156E+00 -C - C: 1.7962859283E+01 -Al - C: 4.3980632518E+00 -:MDSTEP: 5 -:MDTM: 13.60 -:TWIST: 0 -:TEL: 2400 -:TIO: 2550.69583076927 -:TEN: -2.6305078209E+00 -:KEN: 1.1510541599E-02 -:KENIG: 1.2116359578E-02 -:FEN: -2.6420183625E+00 -:UEN: -2.6375479756E+00 -:TSEN: -4.4703868802E-03 -:NPT_NP_HAMIL: -1.4718117493E-04 -:R: - 1.3291973001E+01 1.1429855571E-01 7.1586131778E-02 - 1.3299742606E+01 1.7453720178E+01 4.4244206409E+00 - 8.7972267757E-02 1.7404620531E+01 8.6318147443E+00 - 1.3250973818E+01 5.8039111615E+00 1.2946860606E+01 - 2.9968980981E-02 5.8936747667E+00 4.3342043510E+00 - 1.3276042671E+01 5.8873258038E+00 8.6695522789E+00 - 1.3173867471E+01 1.1555116718E+01 4.3682047087E-02 - 1.3311050879E+01 1.1675278157E+01 4.4048470017E+00 - 5.7396528600E-02 1.1575260097E+01 8.7051400500E+00 - 4.3961680640E+00 1.7475512965E+01 1.2919863725E+01 - 4.4732753142E+00 3.3256795234E-03 4.2898417321E+00 - 4.4760780109E+00 1.7401160743E+01 8.7491210994E+00 - 4.5488376337E+00 5.8186964203E+00 6.0888542450E-02 - 4.5886386023E+00 5.8843315182E+00 4.3324336990E+00 - 4.3431806574E+00 5.9207193205E+00 8.6321677615E+00 - 4.4681868282E+00 1.1514316672E+01 1.3009473509E+01 - 4.4063905908E+00 1.1752355834E+01 4.3349033114E+00 - 4.4354141677E+00 1.1655558306E+01 8.6102697063E+00 - 8.9149593342E+00 2.9959882678E-02 7.7621069793E-02 - 8.8213014683E+00 1.7473290896E+01 4.2868986862E+00 -:V: - -2.9352074412E-04 6.9477675007E-04 4.2398704759E-04 - -2.4280501219E-04 -1.6036447501E-04 4.9808135933E-04 - 4.6205140958E-04 -4.5678476670E-04 -2.6988507062E-04 - -4.8823686473E-04 -1.3928910179E-04 -4.3316690316E-04 - 1.2253396908E-04 4.0435388686E-04 -3.9545247669E-05 - -3.4812108256E-04 3.6489668204E-04 -6.9745547792E-05 - -9.5533365359E-04 -5.9317159981E-04 2.6315623889E-04 - -1.3762706640E-04 1.3562393600E-04 3.8693162544E-04 - 2.8073903970E-04 -4.7027425190E-04 1.5698375797E-04 - -1.6393038795E-04 -2.6445123956E-05 -5.8897926808E-04 - 2.9996338328E-04 2.1158825346E-05 -2.9822651723E-04 - 2.8487485159E-04 -4.7759694909E-04 3.9159360132E-04 - 7.0740860210E-04 -5.0040249923E-05 3.5232747265E-04 - 9.5334899358E-04 3.4754838234E-04 -4.1282233492E-05 - -5.2582032901E-04 5.6695106952E-04 -2.7809311857E-04 - 2.2202819574E-04 -8.4182543903E-04 -7.0718410714E-05 - -1.3945999182E-04 6.0159701166E-04 -3.7721036921E-05 - 3.4873493712E-05 1.6533453454E-05 -4.1125019466E-04 - 2.0398504812E-04 1.7841991304E-04 5.8518918654E-04 - -3.6789785180E-04 -3.8352324415E-05 -4.3793201908E-04 -:F: - -8.6795787308E-02 8.0692375952E-03 -9.4234999526E-03 - -8.2244849636E-02 -2.8906998831E-03 -1.4436707543E-02 - -5.3766354152E-02 -3.6850466638E-03 2.8762778739E-02 - -3.9829648085E-02 -3.1852919635E-03 1.2990737038E-02 - -4.1076577180E-02 4.9054945887E-04 -6.4171732513E-03 - -5.5590643610E-02 8.9992973655E-05 -8.0632267533E-03 - -4.3196240478E-02 -2.1133860816E-03 6.8095552596E-04 - -5.4333119320E-02 4.4688488449E-03 -5.3606409211E-03 - -5.1887045229E-02 -1.2384662145E-03 8.6825785604E-03 - 8.1566520239E-02 6.9323354723E-04 2.2151153418E-02 - 8.1000295962E-02 1.4613082776E-03 5.5249870313E-03 - 6.0196888843E-02 -3.8752449556E-03 -3.2748079905E-02 - 3.9540899430E-02 -2.9554575507E-03 -1.8831870481E-02 - 4.7656507696E-02 -1.3680830195E-04 5.8737697562E-03 - 4.8765687602E-02 1.2173848221E-03 1.4244087112E-02 - 4.0524710908E-02 -5.5860371268E-03 -6.6816416077E-03 - 5.4190343854E-02 6.5835632219E-03 -1.0036115687E-02 - 5.5370240427E-02 2.7432238933E-03 1.3078503133E-02 - 1.9993828328E-03 -1.2787831641E-03 4.4980543561E-02 - -2.0912127953E-03 1.1278792709E-03 -4.4971137772E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020225845E+01 -:STRIO: - -1.8021206119E+00 1.6457196755E-01 -8.3559849805E-02 - 1.6457196755E-01 -1.6150790847E+00 4.9621014372E-02 - -8.3559849805E-02 4.9621014372E-02 -1.0232439346E+00 -:STRESS: - -1.0386521686E+01 -8.1421458557E-02 3.0854844142E-01 - -8.1421458557E-02 1.7338150809E+00 -1.5786833949E-01 - 3.0854844142E-01 -1.5786833949E-01 -2.2200036020E+01 -:PRESIO: 1.4801478771E+00 -:PRES: 1.0284247542E+01 -:PRESIG: 1.5675503996E+00 -:MIND: -Al - Al: 4.1721706459E+00 -C - C: 1.7944263336E+01 -Al - C: 4.3778302928E+00 -:MDSTEP: 6 -:MDTM: 14.79 -:TWIST: 0 -:TEL: 2400 -:TIO: 2627.44419212646 -:TEN: -2.6306257846E+00 -:KEN: 1.1856884426E-02 -:KENIG: 1.2480930975E-02 -:FEN: -2.6424826690E+00 -:UEN: -2.6380233490E+00 -:TSEN: -4.4593199908E-03 -:NPT_NP_HAMIL: -1.9728437519E-04 -:R: - 1.3276866268E+01 1.4321796079E-01 8.8737091238E-02 - 1.3286884140E+01 1.7447009537E+01 4.4444545094E+00 - 1.0515585489E-01 1.7385663445E+01 8.6216908338E+00 - 1.3229467873E+01 5.7980590746E+00 1.2929461780E+01 - 3.3596791616E-02 5.9103598833E+00 4.3323541989E+00 - 1.3259766432E+01 5.9023705520E+00 8.6664025008E+00 - 1.3132990395E+01 1.1530592002E+01 5.4553389288E-02 - 1.3303495114E+01 1.1681023633E+01 4.4206135594E+00 - 6.7171242251E-02 1.1555831722E+01 8.7119166540E+00 - 4.3922367376E+00 1.7474446874E+01 1.2896359441E+01 - 4.4884468190E+00 4.2485124351E-03 4.2777420736E+00 - 4.4899067374E+00 1.7381339155E+01 8.7641332175E+00 - 4.5793681866E+00 5.8165312786E+00 7.4759587964E-02 - 4.6295884078E+00 5.8986532832E+00 4.3309378060E+00 - 4.3231951474E+00 5.9441321390E+00 8.6212024528E+00 - 4.4787433048E+00 1.1479421721E+01 1.3006333812E+01 - 4.4025194331E+00 1.1777382744E+01 4.3330029661E+00 - 4.4387701991E+00 1.1656334890E+01 8.5937750508E+00 - 8.9235235475E+00 3.7215106356E-02 1.0524457982E-01 - 8.8059733572E+00 1.7471797739E+01 4.2653484141E+00 -:V: - -3.6435277975E-04 6.9749465131E-04 4.1365566908E-04 - -3.1012779835E-04 -1.6185104432E-04 4.8313131674E-04 - 4.1444352276E-04 -4.5721778264E-04 -2.4428526243E-04 - -5.1869260207E-04 -1.4114395675E-04 -4.1980130788E-04 - 8.7497599178E-05 4.0242112641E-04 -4.4678771735E-05 - -3.9255959106E-04 3.6285779119E-04 -7.6079657813E-05 - -9.8589653973E-04 -5.9150104486E-04 2.6220064923E-04 - -1.8223423541E-04 1.3857265523E-04 3.8021014206E-04 - 2.3575210039E-04 -4.6858458113E-04 1.6333001104E-04 - -9.4817965596E-05 -2.5712595119E-05 -5.6705586400E-04 - 3.6591497634E-04 2.2257408759E-05 -2.9188162397E-04 - 3.3352908777E-04 -4.7806832879E-04 3.6195825758E-04 - 7.3635322967E-04 -5.2220118689E-05 3.3454897762E-04 - 9.8765068795E-04 3.4542047108E-04 -3.6134526509E-05 - -4.8202189041E-04 5.6468366696E-04 -2.6457858488E-04 - 2.5460710425E-04 -8.4161625180E-04 -7.5892335562E-05 - -9.3366781695E-05 6.0361323373E-04 -4.5889370084E-05 - 8.0942674809E-05 1.8730092718E-05 -3.9793823435E-04 - 2.0655656541E-04 1.7498560895E-04 6.6623851918E-04 - -3.6969209829E-04 -3.6012811713E-05 -5.1981685587E-04 -:F: - -8.5819759627E-02 9.8499700198E-03 -1.1429435316E-02 - -8.0906223082E-02 -3.4588007189E-03 -1.8261892965E-02 - -5.2839222535E-02 -4.4891332027E-03 3.5493829145E-02 - -3.6788966751E-02 -3.9902275336E-03 1.6426066641E-02 - -3.7976063261E-02 5.2226186038E-04 -8.1464250774E-03 - -5.6068917178E-02 4.3229573648E-04 -9.9884150786E-03 - -4.0926683079E-02 -2.6429663569E-03 1.0617305944E-03 - -5.3866954814E-02 5.6181286428E-03 -6.8620859536E-03 - -5.1390836531E-02 -1.9450821836E-03 1.0766744273E-02 - 7.9330922398E-02 1.0291294328E-03 2.7974773857E-02 - 7.9021376069E-02 1.7859639292E-03 6.6528498098E-03 - 6.1016019955E-02 -4.9248247929E-03 -4.0709918306E-02 - 3.6311148988E-02 -3.6906486789E-03 -2.2963434763E-02 - 4.6188282506E-02 -2.0740247071E-04 7.2302063370E-03 - 4.7647025247E-02 1.8119137690E-03 1.7113041075E-02 - 3.7662250056E-02 -6.6704942464E-03 -7.5504395498E-03 - 5.3629555116E-02 8.2371003729E-03 -1.2912140635E-02 - 5.5763991680E-02 2.9315239304E-03 1.6055324212E-02 - 2.2367429026E-03 -1.6024051852E-03 4.7534166595E-02 - -2.2236880584E-03 1.4036976761E-03 -4.7484544894E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020232789E+01 -:STRIO: - -1.9358517258E+00 1.6487582152E-01 -2.7710742132E-02 - 1.6487582152E-01 -1.6139132623E+00 4.7063286499E-02 - -2.7710742132E-02 4.7063286499E-02 -9.9900531434E-01 -:STRESS: - -9.9261508454E+00 -1.0321918040E-01 3.7447492780E-01 - -1.0321918040E-01 1.6767792827E+00 -1.9452877696E-01 - 3.7447492780E-01 -1.9452877696E-01 -2.2222854443E+01 -:PRESIO: 1.5162567675E+00 -:PRES: 1.0157408668E+01 -:PRESIG: 1.6147158540E+00 -:MIND: -Al - Al: 4.1344288649E+00 -C - C: 1.7924423380E+01 -Al - C: 4.3546643892E+00 -:MDSTEP: 7 -:MDTM: 18.12 -:TWIST: 0 -:TEL: 2400 -:TIO: 2711.02713095187 -:TEN: -2.6308115887E+00 -:KEN: 1.2234069696E-02 -:KENIG: 1.2877968101E-02 -:FEN: -2.6430456584E+00 -:UEN: -2.6386026874E+00 -:TSEN: -4.4429709274E-03 -:NPT_NP_HAMIL: -2.5109194738E-04 -:R: - 1.3258908360E+01 1.7225480230E-01 1.0536046049E-01 - 1.3271327064E+01 1.7440231077E+01 4.4637027742E+00 - 1.2037957454E-01 1.7366697422E+01 8.6128734834E+00 - 1.3206855691E+01 5.7921141645E+00 1.2912766771E+01 - 3.5883340981E-02 5.9269342911E+00 4.3302371172E+00 - 1.3241676868E+01 5.9173141402E+00 8.6629326310E+00 - 1.3091013494E+01 1.1506165161E+01 6.5377558893E-02 - 1.3294134870E+01 1.1686919050E+01 4.4360216624E+00 - 7.5093354356E-02 1.1536486025E+01 8.7190143102E+00 - 4.3910791213E+00 1.7473424599E+01 1.2874005456E+01 - 4.5062339012E+00 5.2259843101E-03 4.2659663541E+00 - 4.5057387551E+00 1.7361500235E+01 8.7776227078E+00 - 4.6109188048E+00 5.8142552190E+00 8.7729491824E-02 - 4.6718194315E+00 5.9128573462E+00 4.3297039940E+00 - 4.3050115760E+00 5.9674269249E+00 8.6109145650E+00 - 4.4905207218E+00 1.1444565402E+01 1.3002958762E+01 - 4.4005327335E+00 1.1802501355E+01 4.3306712737E+00 - 4.4440287237E+00 1.1657206856E+01 8.5779639061E+00 - 8.9321954238E+00 4.4289856415E-02 1.3634755480E-01 - 8.7905907983E+00 1.7470425149E+01 4.2402761756E+00 -:V: - -4.3227436299E-04 6.9896127723E-04 4.0014859465E-04 - -3.7448264689E-04 -1.6316793132E-04 4.6326609624E-04 - 3.6645826381E-04 -4.5654124262E-04 -2.1238125408E-04 - -5.4430987888E-04 -1.4310309762E-04 -4.0207558576E-04 - 5.5040747588E-05 3.9897139858E-04 -5.1028793802E-05 - -4.3544352897E-04 3.5971506837E-04 -8.3659895043E-05 - -1.0104483541E-03 -5.8799150445E-04 2.6055350292E-04 - -2.2531542172E-04 1.4191172329E-04 3.7082788899E-04 - 1.9069737981E-04 -4.6568058624E-04 1.7071594346E-04 - -2.7865596310E-05 -2.4607723765E-05 -5.3829528683E-04 - 4.2816232950E-04 2.3529246106E-05 -2.8352615794E-04 - 3.8110092910E-04 -4.7755320455E-04 3.2457637302E-04 - 7.5947173411E-04 -5.4788242293E-05 3.1220430070E-04 - 1.0165654617E-03 3.4191356506E-04 -2.9767117768E-05 - -4.3770643363E-04 5.6074119840E-04 -2.4777933420E-04 - 2.8350047706E-04 -8.3904502937E-04 -8.1444946984E-05 - -4.7822904223E-05 6.0464347940E-04 -5.6194811624E-05 - 1.2658074627E-04 2.0989572198E-05 -3.8073216670E-04 - 2.0874535328E-04 1.7030007671E-04 7.4869463910E-04 - -3.7028176691E-04 -3.3040325484E-05 -6.0359355732E-04 -:F: - -8.4255439298E-02 1.1495008445E-02 -1.3347421196E-02 - -7.9347681789E-02 -3.9403570896E-03 -2.1989198076E-02 - -5.1427338560E-02 -5.2397828138E-03 4.1841669067E-02 - -3.3944161078E-02 -4.7810546228E-03 1.9696283323E-02 - -3.4897372313E-02 5.4544011080E-04 -9.7788771084E-03 - -5.6191161253E-02 7.3030336925E-04 -1.1812113602E-02 - -3.8803742417E-02 -3.1717321191E-03 1.4171550751E-03 - -5.3071209552E-02 6.7435126435E-03 -8.2584216786E-03 - -5.0509035794E-02 -2.6210602097E-03 1.2725404201E-02 - 7.6544979367E-02 1.4313989501E-03 3.3683434179E-02 - 7.6657335626E-02 2.1129714607E-03 7.7455189150E-03 - 6.1391324427E-02 -5.9885944963E-03 -4.8353542720E-02 - 3.3242447666E-02 -4.4066500893E-03 -2.6854906818E-02 - 4.4718621198E-02 -2.6554334131E-04 8.6060831902E-03 - 4.6223349954E-02 2.3433464680E-03 1.9660769179E-02 - 3.4972941299E-02 -7.6369465475E-03 -8.2113194969E-03 - 5.2726548035E-02 9.8290823529E-03 -1.5704171303E-02 - 5.5777860408E-02 3.0778770381E-03 1.8830947281E-02 - 2.2727111593E-03 -1.9299944307E-03 5.0513981134E-02 - -2.0809770879E-03 1.6727749222E-03 -5.0411273548E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020241203E+01 -:STRIO: - -2.0849110153E+00 1.6480827638E-01 2.5300132366E-02 - 1.6480827638E-01 -1.6046550804E+00 4.5137515593E-02 - 2.5300132366E-02 4.5137515593E-02 -9.6753910889E-01 -:STRESS: - -9.3973623713E+00 -1.2472096166E-01 4.2996069613E-01 - -1.2472096166E-01 1.6108981617E+00 -2.2435934843E-01 - 4.2996069613E-01 -2.2435934843E-01 -2.2234908092E+01 -:PRESIO: 1.5523684015E+00 -:PRES: 1.0007124101E+01 -:PRESIG: 1.6660813094E+00 -:MIND: -Al - Al: 4.0995152782E+00 -C - C: 1.7903420714E+01 -Al - C: 4.3287157518E+00 -:MDSTEP: 8 -:MDTM: 13.58 -:TWIST: 0 -:TEL: 2400 -:TIO: 2794.89679890965 -:TEN: -2.6310953908E+00 -:KEN: 1.2612548890E-02 -:KENIG: 1.3276367252E-02 -:FEN: -2.6437079397E+00 -:UEN: -2.6392870599E+00 -:TSEN: -4.4208798144E-03 -:NPT_NP_HAMIL: -3.1072403544E-04 -:R: - 1.3238261583E+01 2.0133639692E-01 1.2132204292E-01 - 1.3253221329E+01 1.7433398811E+01 4.4819599062E+00 - 1.3364485857E-01 1.7347780418E+01 8.6056073844E+00 - 1.3183346531E+01 5.7860763507E+00 1.2896955076E+01 - 3.6938391586E-02 5.9433267207E+00 4.3278089058E+00 - 1.3221868117E+01 5.9321018838E+00 8.6590984322E+00 - 1.3048206579E+01 1.1481924832E+01 7.6119497844E-02 - 1.3283057311E+01 1.1692975666E+01 4.4509587973E+00 - 8.1177164554E-02 1.1517284280E+01 8.7264660601E+00 - 4.3925759771E+00 1.7472464085E+01 1.2853085826E+01 - 4.5264498225E+00 6.2645021885E-03 4.2546010124E+00 - 4.5234966900E+00 1.7341695078E+01 8.7892819271E+00 - 4.6432339086E+00 5.8118547241E+00 9.9615918983E-02 - 4.7150814261E+00 5.9268801717E+00 4.3287825482E+00 - 4.2886427842E+00 5.9905203370E+00 8.6014306041E+00 - 4.5033618642E+00 1.1409867916E+01 1.2999342996E+01 - 4.4003889242E+00 1.1827654721E+01 4.3278266562E+00 - 4.4511476214E+00 1.1658174432E+01 8.5629949680E+00 - 8.9409383568E+00 5.1129342043E-02 1.7098811824E-01 - 8.7752333380E+00 1.7469198813E+01 4.2116018068E+00 -:V: - -4.9574891819E-04 6.9827698323E-04 3.8325096879E-04 - -4.3473605997E-04 -1.6404925503E-04 4.3828921983E-04 - 3.1851219423E-04 -4.5421542117E-04 -1.7462429061E-04 - -5.6447747692E-04 -1.4497370136E-04 -3.7989127130E-04 - 2.5332777076E-05 3.9359796001E-04 -5.8383266387E-05 - -4.7562709514E-04 3.5506791063E-04 -9.2221997884E-05 - -1.0278350973E-03 -5.8203353634E-04 2.5792305692E-04 - -2.6598282415E-04 1.4542516114E-04 3.5857341279E-04 - 1.4607811874E-04 -4.6105232348E-04 1.7876342716E-04 - 3.5940943138E-05 -2.3062856428E-05 -5.0253699100E-04 - 4.8540366364E-04 2.4935810456E-05 -2.7297115699E-04 - 4.2638505197E-04 -4.7554081261E-04 2.7978772667E-04 - 7.7591664094E-04 -5.7638186055E-05 2.8540290583E-04 - 1.0387619909E-03 3.3670149233E-04 -2.2204365644E-05 - -3.9303039277E-04 5.5449497566E-04 -2.2787724770E-04 - 3.0832814503E-04 -8.3311992753E-04 -8.7056970133E-05 - -3.4529991433E-06 6.0395644701E-04 -6.8381583494E-05 - 1.7093156072E-04 2.3232416745E-05 -3.5957620761E-04 - 2.0992620707E-04 1.6422261069E-04 8.3175065139E-04 - -3.6874735300E-04 -2.9445517701E-05 -6.8857702777E-04 -:F: - -8.2161136110E-02 1.2982783018E-02 -1.5174025598E-02 - -7.7622194945E-02 -4.3251872015E-03 -2.5525620405E-02 - -4.9556242961E-02 -5.9292364743E-03 4.7695435186E-02 - -3.1321508774E-02 -5.5508007955E-03 2.2733430311E-02 - -3.1878769188E-02 5.6709695633E-04 -1.1302016713E-02 - -5.5969683504E-02 9.7497735294E-04 -1.3494481653E-02 - -3.6855239069E-02 -3.6924295531E-03 1.7531805953E-03 - -5.1963038563E-02 7.8287825233E-03 -9.5247752864E-03 - -4.9250002122E-02 -3.2474117210E-03 1.4512962169E-02 - 7.3281484359E-02 1.8928872083E-03 3.9135336873E-02 - 7.3951547172E-02 2.4509374648E-03 8.8042507914E-03 - 6.1327859573E-02 -7.0521775157E-03 -5.5524565728E-02 - 3.0367269980E-02 -5.1023922483E-03 -3.0440460520E-02 - 4.3276487061E-02 -3.0522523339E-04 9.9590691982E-03 - 4.4509726199E-02 2.7993937558E-03 2.1882598381E-02 - 3.2481289810E-02 -8.4843420318E-03 -8.6712066970E-03 - 5.1505640729E-02 1.1332866203E-02 -1.8349397925E-02 - 5.5418343716E-02 3.1864625047E-03 2.1362295195E-02 - 2.0595573040E-03 -2.2607716194E-03 5.3986776148E-02 - -1.6013906668E-03 1.9337874063E-03 -5.3818784322E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020251168E+01 -:STRIO: - -2.2377497906E+00 1.6397744140E-01 7.3650585365E-02 - 1.6397744140E-01 -1.5837372729E+00 4.3837701133E-02 - 7.3650585365E-02 4.3837701133E-02 -9.3183508014E-01 -:STRESS: - -8.8169413453E+00 -1.4527907082E-01 4.7343394367E-01 - -1.4527907082E-01 1.5388575816E+00 -2.4320575304E-01 - 4.7343394367E-01 -2.4320575304E-01 -2.2224377226E+01 -:PRESIO: 1.5844407145E+00 -:PRES: 9.8341536633E+00 -:PRESIG: 1.7176227051E+00 -:MIND: -Al - Al: 4.0680146131E+00 -C - C: 1.7881363517E+01 -Al - C: 4.3002343878E+00 -:MDSTEP: 9 -:MDTM: 13.74 -:TWIST: 0 -:TEL: 2400 -:TIO: 2872.00065597781 -:TEN: -2.6315093527E+00 -:KEN: 1.2960495965E-02 -:KENIG: 1.3642627331E-02 -:FEN: -2.6444698487E+00 -:UEN: -2.6400769298E+00 -:TSEN: -4.3929188973E-03 -:NPT_NP_HAMIL: -3.7739155534E-04 -:R: - 1.3215151147E+01 2.3035450972E-01 1.3648186795E-01 - 1.3232763480E+01 1.7426537606E+01 4.4990196271E+00 - 1.4497314633E-01 1.7328991232E+01 8.6001102944E+00 - 1.3159172415E+01 5.7799535134E+00 1.2882204346E+01 - 3.6878546564E-02 5.9594511862E+00 4.3250351838E+00 - 1.3200481803E+01 5.9466638322E+00 8.6548685883E+00 - 1.3004882806E+01 1.1457982605E+01 8.6733374607E-02 - 1.3270386871E+01 1.1699195321E+01 4.4653070464E+00 - 8.5460449813E-02 1.1498307582E+01 8.7342875141E+00 - 4.3965669235E+00 1.7471585517E+01 1.2833880830E+01 - 4.5488546102E+00 7.3691020528E-03 4.2437383769E+00 - 4.5430524346E+00 1.7321994694E+01 8.7988283055E+00 - 4.6760267233E+00 5.8093208412E+00 1.1024699482E-01 - 4.7590731415E+00 5.9406465865E+00 4.3282203936E+00 - 4.2740918509E+00 6.0133050466E+00 8.5928667733E+00 - 4.5170949318E+00 1.1375487108E+01 1.2995494256E+01 - 4.4020190495E+00 1.1852756749E+01 4.3244014525E+00 - 4.4600476581E+00 1.1659234630E+01 8.5490244437E+00 - 8.9496870887E+00 5.7674219761E-02 2.0919224996E-01 - 8.7600214732E+00 1.7468143386E+01 4.1792728483E+00 -:V: - -5.5322085847E-04 6.9463964038E-04 3.6289541460E-04 - -4.8972286671E-04 -1.6424448932E-04 4.0828207559E-04 - 2.7117813594E-04 -4.4977814973E-04 -1.3177426055E-04 - -5.7868336974E-04 -1.4656933501E-04 -3.5338102725E-04 - -1.4325785131E-06 3.8598970810E-04 -6.6490353706E-05 - -5.1194857393E-04 3.4858595523E-04 -1.0143988741E-04 - -1.0370905372E-03 -5.7313236977E-04 2.5407483673E-04 - -3.0330675991E-04 1.4888698291E-04 3.4337514667E-04 - 1.0253388126E-04 -4.5426685248E-04 1.8704432388E-04 - 9.5535831522E-05 -2.1031289859E-05 -4.6000691781E-04 - 5.3632893800E-04 2.6442065958E-05 -2.6012232906E-04 - 4.6812814921E-04 -4.7159053632E-04 2.2833445911E-04 - 7.8499898292E-04 -6.0656441403E-05 2.5448604787E-04 - 1.0530798320E-03 3.2954236224E-04 -1.3549566870E-05 - -3.4832227389E-04 5.4542356441E-04 -2.0518624130E-04 - 3.2874409390E-04 -8.2301257523E-04 -9.2409849577E-05 - 3.9022166306E-05 6.0089583660E-04 -8.2085615070E-05 - 2.1305032306E-04 2.5379173331E-05 -3.3461160008E-04 - 2.0942836693E-04 1.5667219767E-04 9.1453218660E-04 - -3.6414374745E-04 -2.5264961680E-05 -7.7398525095E-04 -:F: - -7.9606053203E-02 1.4300306273E-02 -1.6902429651E-02 - -7.5770414034E-02 -4.6077228226E-03 -2.8770123890E-02 - -4.7276053184E-02 -6.5493647773E-03 5.2945719720E-02 - -2.8934972789E-02 -6.2914070081E-03 2.5470348362E-02 - -2.8954960513E-02 5.9425184358E-04 -1.2702899395E-02 - -5.5428384981E-02 1.1576298118E-03 -1.4994540640E-02 - -3.5092239489E-02 -4.1993624112E-03 2.0758762877E-03 - -5.0572116080E-02 8.8557131499E-03 -1.0642555957E-02 - -4.7638125652E-02 -3.8046806271E-03 1.6091809408E-02 - 6.9627176119E-02 2.4008354009E-03 4.4170780015E-02 - 7.0944546969E-02 2.8087544995E-03 9.8255535971E-03 - 6.0844013907E-02 -8.0987381750E-03 -6.2057028770E-02 - 2.7708197718E-02 -5.7753600269E-03 -3.3656768598E-02 - 4.1884796320E-02 -3.2028651609E-04 1.1244512326E-02 - 4.2534383876E-02 3.1676868221E-03 2.3778623385E-02 - 3.0195726458E-02 -9.2145951976E-03 -8.9421733900E-03 - 5.0002272462E-02 1.2720143363E-02 -2.0787347763E-02 - 5.4707239368E-02 3.2662365514E-03 2.3608624078E-02 - 1.5513739944E-03 -2.5968646489E-03 5.8032914537E-02 - -7.2640726701E-04 2.1868244954E-03 -5.7788893660E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020262807E+01 -:STRIO: - -2.3816338361E+00 1.6203445826E-01 1.1555320418E-01 - 1.6203445826E-01 -1.5483428256E+00 4.3129941737E-02 - 1.1555320418E-01 4.3129941737E-02 -8.9600320142E-01 -:STRESS: - -8.2048781963E+00 -1.6412447782E-01 5.0473488810E-01 - -1.6412447782E-01 1.4632495327E+00 -2.4687278622E-01 - 5.0473488810E-01 -2.4687278622E-01 -2.2178857490E+01 -:PRESIO: 1.6086599544E+00 -:PRES: 9.6401620512E+00 -:PRESIG: 1.7650058235E+00 -:MIND: -Al - Al: 4.0404807007E+00 -C - C: 1.7858385974E+01 -Al - C: 4.2695771351E+00 -:MDSTEP: 10 -:MDTM: 13.56 -:TWIST: 0 -:TEL: 2400 -:TIO: 2935.64256511282 -:TEN: -2.6320854678E+00 -:KEN: 1.3247693220E-02 -:KENIG: 1.3944940232E-02 -:FEN: -2.6453331611E+00 -:UEN: -2.6409739674E+00 -:TSEN: -4.3591936570E-03 -:NPT_NP_HAMIL: -4.5207007720E-04 -:R: - 1.3189862405E+01 2.5917177267E-01 1.5070136046E-01 - 1.3210195631E+01 1.7419681851E+01 4.5146876986E+00 - 1.5441119660E-01 1.7310424989E+01 8.5965603167E+00 - 1.3134582167E+01 5.7737608320E+00 1.2868680010E+01 - 3.5827642629E-02 5.9752120429E+00 4.3218928012E+00 - 1.3177704861E+01 5.9609186914E+00 8.6502269134E+00 - 1.2961387867E+01 1.1434466583E+01 9.7165677100E-02 - 1.3256284706E+01 1.1705570412E+01 4.4789495629E+00 - 8.8008852093E-02 1.1479652370E+01 8.7424757199E+00 - 4.4028494303E+00 1.7470810163E+01 1.2816649279E+01 - 4.5731576180E+00 8.5436728558E-03 4.2334718885E+00 - 4.5642280307E+00 1.7302485844E+01 8.8060216775E+00 - 4.7089883798E+00 5.8066493377E+00 1.1947128917E-01 - 4.8034529438E+00 5.9540741983E+00 4.3280577570E+00 - 4.2613453679E+00 6.0356557539E+00 8.5853233250E+00 - 4.5315359825E+00 1.1341609176E+01 1.2991432773E+01 - 4.4053242749E+00 1.1877697018E+01 4.3203459922E+00 - 4.4706109453E+00 1.1660381538E+01 8.5361972148E+00 - 8.9583469389E+00 6.3863284556E-02 2.5095518753E-01 - 8.7451159210E+00 1.7467281476E+01 4.1432646863E+00 -:V: - -6.0327793518E-04 6.8745290235E-04 3.3921105685E-04 - -5.3836941315E-04 -1.6354810053E-04 3.7365998619E-04 - 2.2515028777E-04 -4.4290874568E-04 -8.4899298885E-05 - -5.8661495188E-04 -1.4773008775E-04 -3.2294933150E-04 - -2.5069936753E-05 3.7598458727E-04 -7.5070257607E-05 - -5.4335748161E-04 3.4005812332E-04 -1.1094373888E-04 - -1.0375975661E-03 -5.6098866757E-04 2.4886662159E-04 - -3.3641552226E-04 1.5208156050E-04 3.2534000219E-04 - 6.0793648122E-05 -4.4503113585E-04 1.9511871299E-04 - 1.4987292651E-04 -1.8496519794E-05 -4.1138594623E-04 - 5.7976266900E-04 2.8020083266E-05 -2.4501801880E-04 - 5.0515640433E-04 -4.6539519404E-04 1.7138477011E-04 - 7.8631986748E-04 -6.3730301761E-05 2.2004828978E-04 - 1.0587065110E-03 3.2032364393E-04 -3.9867260315E-06 - -3.0407491485E-04 5.3318938096E-04 -1.8016573035E-04 - 3.4449983042E-04 -8.0817816013E-04 -9.7210149764E-05 - 7.8848114433E-05 5.9496492589E-04 -9.6852250629E-05 - 2.5199348234E-04 2.7360159903E-05 -3.0621237005E-04 - 2.0658586415E-04 1.4764381208E-04 9.9627448125E-04 - -3.5558078985E-04 -2.0561359426E-05 -8.5909931732E-04 -:F: - -7.6664496566E-02 1.5443352594E-02 -1.8523700060E-02 - -7.3810759144E-02 -4.7895467751E-03 -3.1622711193E-02 - -4.4655396092E-02 -7.0915642693E-03 5.7491035493E-02 - -2.6790715578E-02 -6.9939339305E-03 2.7845400234E-02 - -2.6146341764E-02 6.3493998100E-04 -1.3969822932E-02 - -5.4604389843E-02 1.2698184361E-03 -1.6273143406E-02 - -3.3520386837E-02 -4.6895880226E-03 2.3909392351E-03 - -4.8937863502E-02 9.8068891856E-03 -1.1593902266E-02 - -4.5714230809E-02 -4.2739704653E-03 1.7427781946E-02 - 6.5668347086E-02 2.9347662756E-03 4.8619578001E-02 - 6.7667217145E-02 3.1952123239E-03 1.0807930047E-02 - 5.9968935065E-02 -9.1113478230E-03 -6.7783155298E-02 - 2.5280909463E-02 -6.4202631176E-03 -3.6451184201E-02 - 4.0550695170E-02 -3.0522055837E-04 1.2421357630E-02 - 4.0338515305E-02 3.4397913707E-03 2.5355959658E-02 - 2.8120808073E-02 -9.8349165681E-03 -9.0398519529E-03 - 4.8260558946E-02 1.3965870047E-02 -2.2962735729E-02 - 5.3682017297E-02 3.3317305689E-03 2.5532967491E-02 - 7.1172921808E-04 -2.9434073965E-03 6.2773844697E-02 - 5.9484736710E-04 2.4313881438E-03 -6.2446587393E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020276292E+01 -:STRIO: - -2.5040776248E+00 1.5872415027E-01 1.4953972713E-01 - 1.5872415027E-01 -1.4969458926E+00 4.2953422311E-02 - 1.4953972713E-01 4.2953422311E-02 -8.6500391728E-01 -:STRESS: - -7.5838077051E+00 -1.8051546382E-01 5.2484832622E-01 - -1.8051546382E-01 1.3870522842E+00 -2.3184331129E-01 - 5.2484832622E-01 -2.3184331129E-01 -2.2085753088E+01 -:PRESIO: 1.6220091449E+00 -:PRES: 9.4275028364E+00 -:PRESIG: 1.8041154852E+00 -:MIND: -Al - Al: 4.0174008869E+00 -C - C: 1.7834643407E+01 -Al - C: 4.2372065533E+00 diff --git a/tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.refout b/tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.refout deleted file mode 100644 index 4c95b959..00000000 --- a/tests/Al18C2_NPTNP_onlyc/high_accuracy/Al18C2_NPTNP_onlyc.refout +++ /dev/null @@ -1,572 +0,0 @@ -*************************************************************************** -* SPARC (version June 24, 2024) * -* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * -* Distributed under GNU General Public License 3 (GPL) * -* Start time: Mon Jun 24 20:09:50 2024 * -*************************************************************************** - Input parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.020212061 -LATVEC: -1.000000000000000 0.000000000000000 0.000000000000000 -0.000000000000000 1.000000000000000 0.000000000000000 -0.000000000000000 0.000000000000000 1.000000000000000 -FD_GRID: 89 117 87 -FD_ORDER: 12 -BC: P P P -KPOINT_GRID: 1 1 1 -KPOINT_SHIFT: 0 0 0 -SPIN_TYP: 0 -ELEC_TEMP_TYPE: Fermi-Dirac -ELEC_TEMP: 2400 -EXCHANGE_CORRELATION: GGA_PBE -NSTATES: 72 -CHEB_DEGREE: 42 -CHEFSI_BOUND_FLAG: 0 -CALC_STRESS: 1 -TWTIME: 1E+09 -MD_FLAG: 1 -MD_METHOD: NPT_NP -MD_TIMESTEP: 1 -MD_NSTEP: 10 -ION_VEL_DSTR: 2 -ION_VEL_DSTR_RAND: 0 -ION_TEMP: 2400 -NPT_SCALE_VECS: 3 -NPT_SCALE_CONSTRAINTS: none -NPT_NP_QMASS: 20000 -NPT_NP_BMASS: 1000 -TARGET_PRESSURE: 0.1 GPa -RESTART_FLAG: 1 -MAXIT_SCF: 100 -MINIT_SCF: 2 -MAXIT_POISSON: 3000 -TOL_SCF: 1.00E-06 -POISSON_SOLVER: AAR -TOL_POISSON: 1.00E-08 -TOL_LANCZOS: 1.00E-02 -TOL_PSEUDOCHARGE: 1.00E-09 -MIXING_VARIABLE: density -MIXING_PRECOND: kerker -TOL_PRECOND: 2.24E-05 -PRECOND_KERKER_KTF: 1 -PRECOND_KERKER_THRESH: 0 -MIXING_PARAMETER: 1 -MIXING_HISTORY: 7 -PULAY_FREQUENCY: 1 -PULAY_RESTART: 0 -REFERENCE_CUTOFF: 0.5 -RHO_TRIGGER: 4 -NUM_CHEFSI: 1 -FIX_RAND: 0 -VERBOSITY: 1 -PRINT_FORCES: 1 -PRINT_ATOMS: 1 -PRINT_EIGEN: 0 -PRINT_DENSITY: 0 -PRINT_MDOUT: 1 -PRINT_VELS: 1 -PRINT_RESTART: 1 -PRINT_RESTART_FQ: 1 -PRINT_ENERGY_DENSITY: 0 -OUTPUT_FILE: Al18C2_NPTNP_onlyc/temp_run/Al18C2_NPTNP_onlyc -*************************************************************************** - Cell -*************************************************************************** -Lattice vectors (Bohr): -13.322568219000001 0.000000000000000 0.000000000000000 -0.000000000000000 17.479965394000001 0.000000000000000 -0.000000000000000 0.000000000000000 13.020212061000001 -Volume: 3.0321213535E+03 (Bohr^3) -Density: 1.6809673281E-01 (amu/Bohr^3), 1.8836706501E+00 (g/cc) -*************************************************************************** - Parallelization -*************************************************************************** -NP_SPIN_PARAL: 1 -NP_KPOINT_PARAL: 1 -NP_BAND_PARAL: 24 -NP_DOMAIN_PARAL: 2 2 1 -NP_DOMAIN_PHI_PARAL: 4 6 4 -EIG_SERIAL_MAXNS: 1500 -*************************************************************************** - Initialization -*************************************************************************** -Number of processors : 96 -Mesh spacing in x-direction : 0.149692 (Bohr) -Mesh spacing in y-direction : 0.149401 (Bohr) -Mesh spacing in z-direction : 0.149658 (Bohr) -Number of symmetry adapted k-points: 1 -Output printed to : Al18C2_NPTNP_onlyc/temp_run/Al18C2_NPTNP_onlyc.out -MD output printed to : Al18C2_NPTNP_onlyc/temp_run/Al18C2_NPTNP_onlyc.aimd -Total number of atom types : 2 -Total number of atoms : 20 -Total number of electrons : 62 -Atom type 1 (valence electrons) : Al 3 -Pseudopotential : ../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 -Atomic mass : 26.9815385 -Pseudocharge radii of atom type 1 : 6.74 6.87 6.73 (x, y, z dir) -Number of atoms of type 1 : 18 -Atom type 2 (valence electrons) : C 4 -Pseudopotential : ../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 -Atomic mass : 12.011 -Pseudocharge radii of atom type 2 : 6.89 6.87 6.88 (x, y, z dir) -Number of atoms of type 2 : 2 -Estimated total memory usage : 3.68 GB -Estimated memory per processor : 39.29 MB -WARNING: Atoms are too close to boundary for b calculation. -=================================================================== - Self Consistent Field (SCF#1) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6254185962E+00 1.619E-01 4.444 -2 -2.6410549263E+00 1.735E-01 1.312 -3 -2.6421350980E+00 1.500E-01 1.301 -4 -2.6410862231E+00 2.062E-02 1.283 -5 -2.6411082740E+00 1.594E-02 1.271 -6 -2.6411484994E+00 3.047E-02 1.392 -7 -2.6411051022E+00 2.481E-03 1.257 -8 -2.6411061584E+00 1.170E-03 1.248 -9 -2.6411064705E+00 3.971E-04 1.230 -10 -2.6411065622E+00 1.240E-04 1.209 -11 -2.6411065660E+00 3.653E-05 1.201 -12 -2.6411065663E+00 1.194E-05 1.175 -13 -2.6411065671E+00 6.857E-06 1.202 -14 -2.6411065658E+00 2.087E-06 1.165 -15 -2.6411065657E+00 7.230E-07 1.134 -Total number of SCF: 15 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6411065657E+00 (Ha/atom) -Total free energy : -5.2822131313E+01 (Ha) -Band structure energy : -4.6242161133E+00 (Ha) -Exchange correlation energy : -2.3093638093E+01 (Ha) -Self and correction energy : -7.6944743325E+01 (Ha) --Entropy*kb*T : -8.9539733674E-02 (Ha) -Fermi level : 8.3260168850E-02 (Ha) -RMS force : 5.7179891959E-02 (Ha/Bohr) -Maximum force : 8.4346504832E-02 (Ha/Bohr) -Time for force calculation : 0.092 (sec) -Pressure : 1.0553081450E+01 (GPa) -Maximum stress : 2.2161420625E+01 (GPa) -Time for stress calculation : 0.154 (sec) -MD step time : 22.499 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202134368298 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149692 (Bohr) -Mesh spacing in y-direction : 0.149401 (Bohr) -Mesh spacing in z direction : 0.149658 (Bohr) -=================================================================== - Self Consistent Field (SCF#2) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6414929841E+00 3.483E-02 1.326 -2 -2.6413655508E+00 5.382E-02 1.287 -3 -2.6412693190E+00 3.664E-02 1.407 -4 -2.6412019655E+00 1.147E-02 1.265 -5 -2.6411989908E+00 8.867E-03 1.255 -6 -2.6411947476E+00 1.047E-03 1.246 -7 -2.6411948856E+00 4.056E-04 1.470 -8 -2.6411949693E+00 1.733E-04 1.211 -9 -2.6411949871E+00 4.711E-05 1.194 -10 -2.6411949871E+00 1.558E-05 1.187 -11 -2.6411949880E+00 6.571E-06 1.156 -12 -2.6411949876E+00 6.370E-06 1.137 -13 -2.6411949924E+00 1.628E-06 1.142 -14 -2.6411949934E+00 1.404E-06 1.111 -15 -2.6411949903E+00 2.755E-07 1.180 -Total number of SCF: 15 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6411949903E+00 (Ha/atom) -Total free energy : -5.2823899806E+01 (Ha) -Band structure energy : -4.6238229038E+00 (Ha) -Exchange correlation energy : -2.3092384506E+01 (Ha) -Self and correction energy : -7.6944748915E+01 (Ha) --Entropy*kb*T : -8.9590918476E-02 (Ha) -Fermi level : 8.3254271379E-02 (Ha) -RMS force : 5.7182125660E-02 (Ha/Bohr) -Maximum force : 8.5975957357E-02 (Ha/Bohr) -Time for force calculation : 0.091 (sec) -Pressure : 1.0521966391E+01 (GPa) -Maximum stress : 2.2153849121E+01 (GPa) -Time for stress calculation : 0.150 (sec) -MD step time : 19.187 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202161886166 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149692 (Bohr) -Mesh spacing in y-direction : 0.149401 (Bohr) -Mesh spacing in z direction : 0.149658 (Bohr) -=================================================================== - Self Consistent Field (SCF#3) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6416995620E+00 3.537E-02 1.346 -2 -2.6414654054E+00 3.924E-02 1.282 -3 -2.6414948825E+00 4.816E-02 1.265 -4 -2.6413779426E+00 4.713E-03 1.258 -5 -2.6413801210E+00 7.930E-03 1.246 -6 -2.6413765730E+00 1.149E-03 1.249 -7 -2.6413767285E+00 4.255E-04 1.239 -8 -2.6413768217E+00 1.706E-04 1.216 -9 -2.6413768405E+00 4.358E-05 1.193 -10 -2.6413768408E+00 1.487E-05 1.237 -11 -2.6413768421E+00 7.063E-06 1.153 -12 -2.6413768417E+00 8.398E-06 1.145 -13 -2.6413768445E+00 2.327E-06 1.217 -14 -2.6413768451E+00 1.143E-06 1.119 -15 -2.6413768422E+00 3.931E-07 1.115 -Total number of SCF: 15 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6413768422E+00 (Ha/atom) -Total free energy : -5.2827536843E+01 (Ha) -Band structure energy : -4.6213875957E+00 (Ha) -Exchange correlation energy : -2.3090500993E+01 (Ha) -Self and correction energy : -7.6944766231E+01 (Ha) --Entropy*kb*T : -8.9594156009E-02 (Ha) -Fermi level : 8.3277580641E-02 (Ha) -RMS force : 5.7184574479E-02 (Ha/Bohr) -Maximum force : 8.7097234898E-02 (Ha/Bohr) -Time for force calculation : 0.092 (sec) -Pressure : 1.0466652378E+01 (GPa) -Maximum stress : 2.2159549245E+01 (GPa) -Time for stress calculation : 0.144 (sec) -MD step time : 18.881 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202203203545 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149692 (Bohr) -Mesh spacing in y-direction : 0.149401 (Bohr) -Mesh spacing in z direction : 0.149658 (Bohr) -=================================================================== - Self Consistent Field (SCF#4) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6415431072E+00 2.904E-03 1.234 -2 -2.6416505720E+00 7.103E-04 1.208 -3 -2.6416509194E+00 4.877E-04 1.190 -4 -2.6416509445E+00 6.559E-04 1.190 -5 -2.6416509147E+00 1.861E-04 1.185 -6 -2.6416509190E+00 2.259E-04 1.180 -7 -2.6416509163E+00 3.851E-05 1.176 -8 -2.6416509171E+00 1.467E-05 1.176 -9 -2.6416509154E+00 5.976E-06 1.164 -10 -2.6416509174E+00 1.306E-06 1.276 -11 -2.6416509178E+00 6.555E-07 1.119 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6416509178E+00 (Ha/atom) -Total free energy : -5.2833018356E+01 (Ha) -Band structure energy : -4.6169859206E+00 (Ha) -Exchange correlation energy : -2.3088043987E+01 (Ha) -Self and correction energy : -7.6944793510E+01 (Ha) --Entropy*kb*T : -8.9538176365E-02 (Ha) -Fermi level : 8.3328740780E-02 (Ha) -RMS force : 5.7187224143E-02 (Ha/Bohr) -Maximum force : 8.7668448744E-02 (Ha/Bohr) -Time for force calculation : 0.092 (sec) -Pressure : 1.0387369653E+01 (GPa) -Maximum stress : 2.2176534672E+01 (GPa) -Time for stress calculation : 0.144 (sec) -MD step time : 13.646 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.020225844542 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149692 (Bohr) -Mesh spacing in y-direction : 0.149401 (Bohr) -Mesh spacing in z direction : 0.149658 (Bohr) -=================================================================== - Self Consistent Field (SCF#5) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6419084438E+00 2.924E-03 1.244 -2 -2.6420179930E+00 8.215E-04 1.217 -3 -2.6420184392E+00 1.198E-03 1.206 -4 -2.6420183764E+00 6.116E-04 1.203 -5 -2.6420183650E+00 2.381E-04 1.205 -6 -2.6420183663E+00 3.040E-04 1.186 -7 -2.6420183613E+00 3.352E-05 1.193 -8 -2.6420183626E+00 1.311E-05 1.177 -9 -2.6420183608E+00 5.232E-06 1.163 -10 -2.6420183633E+00 1.414E-06 1.145 -11 -2.6420183625E+00 5.399E-07 1.122 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6420183625E+00 (Ha/atom) -Total free energy : -5.2840367250E+01 (Ha) -Band structure energy : -4.6107690450E+00 (Ha) -Exchange correlation energy : -2.3085099775E+01 (Ha) -Self and correction energy : -7.6944829030E+01 (Ha) --Entropy*kb*T : -8.9407737603E-02 (Ha) -Fermi level : 8.3405076606E-02 (Ha) -RMS force : 5.7191212207E-02 (Ha/Bohr) -Maximum force : 8.7677954134E-02 (Ha/Bohr) -Time for force calculation : 0.092 (sec) -Pressure : 1.0284247542E+01 (GPa) -Maximum stress : 2.2200036020E+01 (GPa) -Time for stress calculation : 0.144 (sec) -MD step time : 13.605 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.020232788601 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149692 (Bohr) -Mesh spacing in y-direction : 0.149401 (Bohr) -Mesh spacing in z direction : 0.149658 (Bohr) -=================================================================== - Self Consistent Field (SCF#6) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6423702958E+00 2.958E-03 1.250 -2 -2.6424822707E+00 8.776E-04 1.226 -3 -2.6424827332E+00 1.165E-03 1.203 -4 -2.6424826941E+00 7.717E-04 1.199 -5 -2.6424826723E+00 2.786E-04 1.191 -6 -2.6424826736E+00 2.803E-04 1.191 -7 -2.6424826678E+00 3.614E-05 1.192 -8 -2.6424826692E+00 1.456E-05 1.189 -9 -2.6424826677E+00 5.421E-06 1.151 -10 -2.6424826701E+00 1.469E-06 1.144 -11 -2.6424826690E+00 5.172E-07 1.123 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6424826690E+00 (Ha/atom) -Total free energy : -5.2849653380E+01 (Ha) -Band structure energy : -4.6029713972E+00 (Ha) -Exchange correlation energy : -2.3081782494E+01 (Ha) -Self and correction energy : -7.6944871308E+01 (Ha) --Entropy*kb*T : -8.9186399815E-02 (Ha) -Fermi level : 8.3502474041E-02 (Ha) -RMS force : 5.7196664984E-02 (Ha/Bohr) -Maximum force : 8.7136014618E-02 (Ha/Bohr) -Time for force calculation : 0.091 (sec) -Pressure : 1.0157408668E+01 (GPa) -Maximum stress : 2.2222854443E+01 (GPa) -Time for stress calculation : 1.349 (sec) -MD step time : 14.792 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202412026591 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149692 (Bohr) -Mesh spacing in y-direction : 0.149401 (Bohr) -Mesh spacing in z direction : 0.149658 (Bohr) -=================================================================== - Self Consistent Field (SCF#7) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6429311439E+00 2.981E-03 1.239 -2 -2.6430452175E+00 1.033E-03 1.207 -3 -2.6430457533E+00 1.460E-03 1.525 -4 -2.6430456866E+00 7.227E-04 1.198 -5 -2.6430456613E+00 3.370E-04 1.225 -6 -2.6430456631E+00 3.320E-04 1.187 -7 -2.6430456577E+00 3.765E-05 1.192 -8 -2.6430456590E+00 1.724E-05 1.183 -9 -2.6430456579E+00 5.398E-06 1.186 -10 -2.6430456600E+00 1.581E-06 1.144 -11 -2.6430456584E+00 7.237E-07 1.125 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6430456584E+00 (Ha/atom) -Total free energy : -5.2860913167E+01 (Ha) -Band structure energy : -4.5939291130E+00 (Ha) -Exchange correlation energy : -2.3078210198E+01 (Ha) -Self and correction energy : -7.6944918345E+01 (Ha) --Entropy*kb*T : -8.8859418549E-02 (Ha) -Fermi level : 8.3616734038E-02 (Ha) -RMS force : 5.7199590995E-02 (Ha/Bohr) -Maximum force : 8.6077104523E-02 (Ha/Bohr) -Time for force calculation : 0.091 (sec) -Pressure : 1.0007124101E+01 (GPa) -Maximum stress : 2.2234908092E+01 (GPa) -Time for stress calculation : 0.144 (sec) -MD step time : 18.122 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202511682122 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149692 (Bohr) -Mesh spacing in y-direction : 0.149401 (Bohr) -Mesh spacing in z direction : 0.149658 (Bohr) -=================================================================== - Self Consistent Field (SCF#8) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6435920990E+00 3.013E-03 1.255 -2 -2.6437074480E+00 1.007E-03 1.231 -3 -2.6437080041E+00 1.179E-03 1.204 -4 -2.6437079640E+00 7.856E-04 1.196 -5 -2.6437079380E+00 1.831E-04 1.204 -6 -2.6437079438E+00 3.972E-04 1.186 -7 -2.6437079370E+00 4.158E-05 1.181 -8 -2.6437079366E+00 1.574E-05 1.184 -9 -2.6437079361E+00 3.535E-06 1.158 -10 -2.6437079360E+00 1.306E-06 1.130 -11 -2.6437079397E+00 5.530E-07 1.119 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6437079397E+00 (Ha/atom) -Total free energy : -5.2874158794E+01 (Ha) -Band structure energy : -4.5840251763E+00 (Ha) -Exchange correlation energy : -2.3074532408E+01 (Ha) -Self and correction energy : -7.6944967240E+01 (Ha) --Entropy*kb*T : -8.8417596289E-02 (Ha) -Fermi level : 8.3744037273E-02 (Ha) -RMS force : 5.7191105052E-02 (Ha/Bohr) -Maximum force : 8.4553273116E-02 (Ha/Bohr) -Time for force calculation : 0.091 (sec) -Pressure : 9.8341536633E+00 (GPa) -Maximum stress : 2.2224377226E+01 (GPa) -Time for stress calculation : 0.151 (sec) -MD step time : 13.586 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.020262807294 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149692 (Bohr) -Mesh spacing in y-direction : 0.149401 (Bohr) -Mesh spacing in z direction : 0.149658 (Bohr) -=================================================================== - Self Consistent Field (SCF#9) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6443508194E+00 3.049E-03 1.241 -2 -2.6444693285E+00 1.337E-03 1.254 -3 -2.6444700152E+00 1.867E-03 1.223 -4 -2.6444698728E+00 7.020E-04 1.258 -5 -2.6444698487E+00 2.846E-04 1.245 -6 -2.6444698570E+00 4.138E-04 1.189 -7 -2.6444698478E+00 4.032E-05 1.188 -8 -2.6444698491E+00 1.946E-05 1.182 -9 -2.6444698487E+00 4.305E-06 1.153 -10 -2.6444698491E+00 1.612E-06 1.143 -11 -2.6444698487E+00 8.772E-07 1.118 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6444698487E+00 (Ha/atom) -Total free energy : -5.2889396974E+01 (Ha) -Band structure energy : -4.5737411668E+00 (Ha) -Exchange correlation energy : -2.3070931141E+01 (Ha) -Self and correction energy : -7.6945014836E+01 (Ha) --Entropy*kb*T : -8.7858377945E-02 (Ha) -Fermi level : 8.3880676995E-02 (Ha) -RMS force : 5.7157757689E-02 (Ha/Bohr) -Maximum force : 8.7284926580E-02 (Ha/Bohr) -Time for force calculation : 0.102 (sec) -Pressure : 9.6401620512E+00 (GPa) -Maximum stress : 2.2178857490E+01 (GPa) -Time for stress calculation : 0.144 (sec) -MD step time : 13.747 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202762918554 -CHEB_DEGREE: 42 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.149692 (Bohr) -Mesh spacing in y-direction : 0.149401 (Bohr) -Mesh spacing in z direction : 0.149658 (Bohr) -=================================================================== - Self Consistent Field (SCF#10) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6452112915E+00 3.067E-03 1.242 -2 -2.6453325537E+00 1.167E-03 1.206 -3 -2.6453331700E+00 9.369E-04 1.205 -4 -2.6453332038E+00 8.802E-04 1.228 -5 -2.6453331566E+00 2.313E-04 1.193 -6 -2.6453331613E+00 2.684E-04 1.183 -7 -2.6453331581E+00 5.550E-05 1.184 -8 -2.6453331587E+00 1.954E-05 1.175 -9 -2.6453331581E+00 3.888E-06 1.159 -10 -2.6453331587E+00 1.256E-06 1.134 -11 -2.6453331611E+00 6.615E-07 1.122 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6453331611E+00 (Ha/atom) -Total free energy : -5.2906663221E+01 (Ha) -Band structure energy : -4.5636585478E+00 (Ha) -Exchange correlation energy : -2.3067629555E+01 (Ha) -Self and correction energy : -7.6945058434E+01 (Ha) --Entropy*kb*T : -8.7183873141E-02 (Ha) -Fermi level : 8.4023753317E-02 (Ha) -RMS force : 5.7086106461E-02 (Ha/Bohr) -Maximum force : 9.0960683672E-02 (Ha/Bohr) -Time for force calculation : 0.090 (sec) -Pressure : 9.4275028364E+00 (GPa) -Maximum stress : 2.2085753088E+01 (GPa) -Time for stress calculation : 0.143 (sec) -MD step time : 13.562 (sec) -*************************************************************************** - Timing info -*************************************************************************** -Total walltime : 161.937 sec -___________________________________________________________________________ - -*************************************************************************** -* Material Physics & Mechanics Group, Georgia Tech * -* PI: Phanish Suryanarayana * -* List of contributors: See the documentation * -* Citation: See README.md or the documentation for details * -* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * -* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * -*************************************************************************** - diff --git a/tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.refaimd b/tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.refaimd deleted file mode 100644 index 610980a1..00000000 --- a/tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.refaimd +++ /dev/null @@ -1,939 +0,0 @@ -:Description: - -:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr -:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu - where atu is the atomic unit of time, hbar/Ha -:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr -:Desc_MDTM: MD time. Unit=second -:Desc_TEL: Electronic temperature. Unit=Kelvin -:Desc_TIO: Ionic temperature. Unit=Kelvin -:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom -:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom -:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom - where N = number of particles, k = Boltzmann constant -:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom -:Desc_UEN: Internal energy. Unit=Ha/atom -:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom -:Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 -:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom -:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa -:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa -:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa - where N = number of particles, k = Boltzmann constant, V = volume -:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr - - -:MDSTEP: 1 -:MDTM: 4.00 -:TWIST: 0 -:TEL: 2400 -:TIO: 2400 -:TEN: -2.6303334274E+00 -:KEN: 1.0830495547E-02 -:KENIG: 1.1400521628E-02 -:FEN: -2.6411639230E+00 -:UEN: -2.6366860994E+00 -:TSEN: -4.4778235924E-03 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 - 0.0000000000E+00 0.0000000000E+00 4.3400663469E+00 - 0.0000000000E+00 0.0000000000E+00 8.6801326939E+00 - 0.0000000000E+00 5.8266493047E+00 0.0000000000E+00 - 0.0000000000E+00 5.8266493047E+00 4.3400663469E+00 - 0.0000000000E+00 5.8266493047E+00 8.6801326939E+00 - 0.0000000000E+00 1.1653298609E+01 0.0000000000E+00 - 0.0000000000E+00 1.1653298609E+01 4.3400663469E+00 - 0.0000000000E+00 1.1653298609E+01 8.6801326939E+00 - 4.4408516321E+00 0.0000000000E+00 0.0000000000E+00 - 4.4408516321E+00 0.0000000000E+00 4.3400663469E+00 - 4.4408516321E+00 0.0000000000E+00 8.6801326939E+00 - 4.4408516321E+00 5.8266493047E+00 0.0000000000E+00 - 4.4408516321E+00 5.8266493047E+00 4.3400663469E+00 - 4.4408516321E+00 5.8266493047E+00 8.6801326939E+00 - 4.4408516321E+00 1.1653298609E+01 0.0000000000E+00 - 4.4408516321E+00 1.1653298609E+01 4.3400663469E+00 - 4.4408516321E+00 1.1653298609E+01 8.6801326939E+00 - 8.8817032643E+00 0.0000000000E+00 0.0000000000E+00 - 8.8817032643E+00 0.0000000000E+00 4.3400663469E+00 -:V: - -5.4115960593E-06 6.8757504739E-04 4.3922438152E-04 - 3.8694989004E-05 -1.5727041676E-04 5.1733352092E-04 - 6.4493512096E-04 -4.5410623326E-04 -3.0784978494E-04 - -3.2920353408E-04 -1.3619507306E-04 -4.4905699411E-04 - 2.8658596847E-04 4.0521884520E-04 -3.3919761855E-05 - -1.7257170604E-04 3.6971498788E-04 -5.9862979356E-05 - -7.9421449907E-04 -5.9309718414E-04 2.6589589603E-04 - 4.2828044862E-05 1.3096756605E-04 3.9314269459E-04 - 4.5465738595E-04 -4.7430305976E-04 1.4680556482E-04 - -4.4755494676E-04 -2.7196430316E-05 -6.1824709024E-04 - 1.9833970038E-05 1.9314745507E-05 -3.0782221035E-04 - 9.7647151403E-05 -4.7512767927E-04 4.3477905793E-04 - 5.4955924937E-04 -4.6798769662E-05 3.8047920243E-04 - 7.8609552254E-04 3.4903251115E-04 -5.0995713773E-05 - -6.9672186847E-04 5.7127171699E-04 -2.9842613860E-04 - 6.0936489813E-05 -8.3800668387E-04 -5.9302851573E-05 - -3.2116552146E-04 5.9649571820E-04 -2.8067877708E-05 - -1.4190760424E-04 9.6824119483E-06 -4.3002551677E-04 - 1.9870593859E-04 1.8287976962E-04 2.8359561204E-04 - -3.6274411453E-04 -4.1742848824E-05 -1.3552040525E-04 -:F: - -8.4207455903E-02 -3.0226923256E-08 -4.3603521068E-04 - -8.4294245284E-02 -2.8801643703E-08 3.6530770398E-04 - -5.2741273136E-02 -1.7574105007E-08 5.2788605106E-05 - -5.2861637400E-02 1.4815602755E-04 -1.1995721439E-03 - -5.2870593292E-02 1.3656476530E-04 1.1890989414E-03 - -5.0258812686E-02 -1.5791001579E-03 8.2901675661E-06 - -5.2861671992E-02 -1.4811495140E-04 -1.1995357160E-03 - -5.2870635298E-02 -1.3651901284E-04 1.1890553186E-03 - -5.0258888152E-02 1.5791402195E-03 8.2966518570E-06 - 8.4232894973E-02 -3.2905881027E-08 -4.3519521112E-04 - 8.4295550130E-02 -2.7648999621E-08 3.7215867902E-04 - 5.2752281283E-02 -2.0579517450E-08 5.6371608111E-05 - 5.2860994304E-02 1.5000715676E-04 -1.2002466620E-03 - 5.2872096257E-02 1.3766419661E-04 1.1896074632E-03 - 5.0260289802E-02 -1.5777692656E-03 8.1804496285E-06 - 5.2861030517E-02 -1.4996628318E-04 -1.2002091561E-03 - 5.2872135991E-02 -1.3761867785E-04 1.1895627709E-03 - 5.0260364787E-02 1.5778097146E-03 8.1870768251E-06 - -4.8124380051E-05 -1.2326635322E-08 3.7962176731E-02 - 5.6994799312E-06 -8.3667926214E-08 -3.7928288067E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020212061E+01 -:STRIO: - -1.5729135264E+00 1.6646213304E-01 -3.0701669489E-01 - 1.6646213304E-01 -1.6073820576E+00 6.5632546225E-02 - -3.0701669489E-01 6.5632546225E-02 -1.0232852406E+00 -:STRESS: - -1.1270966186E+01 -1.1428504158E-07 9.0104990146E-04 - -1.1428504158E-07 1.8844178374E+00 5.3374557937E-09 - 9.0104990146E-04 5.3374557937E-09 -2.2117981642E+01 -:PRESIO: 1.4011936082E+00 -:PRES: 1.0501509997E+01 -:PRESIG: 1.4749406402E+00 -:MIND: -Al - Al: 4.3400663469E+00 -C - C: 4.3400663469E+00 -Al - C: 4.4408516321E+00 -:MDSTEP: 2 -:MDTM: 3.09 -:TWIST: 0 -:TEL: 2400 -:TIO: 2408.99198513338 -:TEN: -2.6303877790E+00 -:KEN: 1.0871073737E-02 -:KENIG: 1.1443235512E-02 -:FEN: -2.6412588528E+00 -:UEN: -2.6367786225E+00 -:TSEN: -4.4802302322E-03 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 1.3319418421E+01 2.8424802924E-02 1.8142672813E-02 - 1.3321238801E+01 1.7473463731E+01 4.3614664060E+00 - 2.4829363830E-02 1.7461192344E+01 8.6674087313E+00 - 1.3307121869E+01 5.8210240591E+00 1.3001607440E+01 - 1.0010480871E-02 5.8434060633E+00 4.3387058588E+00 - 1.3313687575E+01 5.8418786938E+00 8.6776591225E+00 - 1.3287898009E+01 1.1628774436E+01 1.0950628941E-02 - 1.3322501586E+01 1.1658708151E+01 4.3563608996E+00 - 1.7049416348E-02 1.1633745482E+01 8.6862029360E+00 - 4.4252763794E+00 1.7478841075E+01 1.2994639571E+01 - 4.4446007213E+00 7.9848330206E-04 4.3273541643E+00 - 4.4467214896E+00 1.7460323303E+01 8.6981096199E+00 - 4.4654076101E+00 5.8247198253E+00 1.5687553368E-02 - 4.4751865607E+00 5.8410833215E+00 4.3379999454E+00 - 4.4137951598E+00 5.8502112276E+00 8.6677967610E+00 - 4.4452076256E+00 1.1618649652E+01 1.3017720110E+01 - 4.4294116635E+00 1.1677953352E+01 4.3389477956E+00 - 4.4367315485E+00 1.1653753713E+01 8.6623563565E+00 - 8.8899141417E+00 7.5603688072E-03 1.4687318513E-02 - 8.8667076293E+00 1.7478239711E+01 4.3315036577E+00 -:V: - -7.6188640990E-05 6.8755118358E-04 4.3884266141E-04 - -3.2156532481E-05 -1.5726498836E-04 5.1762262972E-04 - 6.0058317850E-04 -4.5409050405E-04 -3.0779474234E-04 - -3.7362287029E-04 -1.3606582448E-04 -4.5004967791E-04 - 2.4213775515E-04 4.0531958024E-04 -3.2919135961E-05 - -2.1480877178E-04 3.6837491985E-04 -5.9853935920E-05 - -8.3861774230E-04 -5.9320111345E-04 2.6487845525E-04 - -1.6117526096E-06 1.3084827974E-04 3.9412847745E-04 - 4.1239851058E-04 -4.7295933196E-04 1.4680744845E-04 - -3.7674081556E-04 -2.7195515066E-05 -6.1859144150E-04 - 9.0684559045E-05 1.9314052620E-05 -3.0749873488E-04 - 1.4198260080E-04 -4.7511122377E-04 4.3481136494E-04 - 5.9397040526E-04 -4.6671064578E-05 3.7945719146E-04 - 8.3050780896E-04 3.4913611827E-04 -4.9994068433E-05 - -6.5445342256E-04 5.6992577956E-04 -2.9840891634E-04 - 1.0536461682E-04 -8.3810367816E-04 -6.0309583665E-05 - -2.7671481261E-04 5.9635936762E-04 -2.7067064847E-05 - -9.9658330857E-05 1.1008241546E-05 -4.3000372635E-04 - 1.9860818459E-04 1.8287340586E-04 3.5526308675E-04 - -3.6272077677E-04 -4.1741559564E-05 -2.0712902776E-04 -:F: - -8.5793066450E-02 2.1038561185E-03 -2.8342254673E-03 - -8.4334551919E-02 -7.8432537322E-04 -3.1544193123E-03 - -5.3637485359E-02 -9.8617595579E-04 7.3207293470E-03 - -4.9585517299E-02 -6.8981188749E-04 2.3192533704E-03 - -5.0086857165E-02 2.6450041828E-04 -7.9336221111E-04 - -5.2050342703E-02 -1.1228392997E-03 -2.0133837433E-03 - -5.0434642448E-02 -6.0335759867E-04 -6.6957734262E-04 - -5.3708490418E-02 9.9601037085E-04 -4.7984798886E-04 - -5.1145937293E-02 8.9830924160E-04 2.1406998057E-03 - 8.4462332041E-02 8.2343655820E-05 4.9941694123E-03 - 8.4200062612E-02 4.1044073018E-04 1.7592334902E-03 - 5.5167073890E-02 -9.0452665120E-04 -8.1050451247E-03 - 4.9591435911E-02 -6.4123031397E-04 -5.6713587797E-03 - 5.1730899675E-02 7.3589730570E-05 2.2183046687E-03 - 5.0280468902E-02 -8.3918226129E-04 3.9301270336E-03 - 4.9719302582E-02 -1.6583142173E-03 -2.8595423356E-03 - 5.3714112304E-02 1.5160852924E-03 -1.4681496268E-03 - 5.2005527384E-02 1.9156925474E-03 3.3701654622E-03 - 5.7533721931E-04 -3.1008622447E-04 3.9292154318E-02 - -6.6966146604E-04 2.7902167743E-04 -3.9295924975E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020213434E+01 -:STRIO: - -1.5749732089E+00 1.6498851204E-01 -2.5330879981E-01 - 1.6498851204E-01 -1.6056460374E+00 6.0871972051E-02 - -2.5330879981E-01 6.0871972051E-02 -1.0384179580E+00 -:STRESS: - -1.1182460597E+01 -1.9024766757E-02 7.7085699568E-02 - -1.9024766757E-02 1.8839871837E+00 -3.7094127215E-02 - 7.7085699568E-02 -3.7094127215E-02 -2.2108768015E+01 -:PRESIO: 1.4063457348E+00 -:PRES: 1.0469080476E+01 -:PRESIG: 1.4804665859E+00 -:MIND: -Al - Al: 4.2966233745E+00 -C - C: 1.7996112872E+01 -Al - C: 4.4295547662E+00 -:MDSTEP: 3 -:MDTM: 3.09 -:TWIST: 0 -:TEL: 2400 -:TIO: 2438.01665003708 -:TEN: -2.6304371194E+00 -:KEN: 1.1002053530E-02 -:KENIG: 1.1581108979E-02 -:FEN: -2.6414391730E+00 -:UEN: -2.6369589434E+00 -:TSEN: -4.4802295506E-03 -:NPT_NP_HAMIL: -5.4349901546E-05 -:R: - 1.3313288603E+01 5.6916860616E-02 3.6183154790E-02 - 1.3316979661E+01 1.7466936153E+01 4.3827529393E+00 - 4.7790126325E-02 1.7442388887E+01 8.6549426358E+00 - 1.3289955965E+01 5.8153760032E+00 1.2983088586E+01 - 1.8278761992E-02 5.8601685694E+00 4.3373185441E+00 - 1.3303000396E+01 5.8570659445E+00 8.6751170242E+00 - 1.3251482693E+01 1.1604234337E+01 2.1875748114E-02 - 1.3320568998E+01 1.1664151185E+01 4.3726358955E+00 - 3.2318392029E-02 1.1614227581E+01 8.6923472216E+00 - 4.4126387601E+00 1.7477719847E+01 1.2969247212E+01 - 4.4512743628E+00 1.6110623394E-03 4.3147061680E+00 - 4.4545067845E+00 1.7440653821E+01 8.7158021831E+00 - 4.4916814756E+00 5.8227684643E+00 3.1174850510E-02 - 4.5113116987E+00 5.8555169303E+00 4.3360114951E+00 - 4.3884911151E+00 5.8737391555E+00 8.6556008175E+00 - 4.4512900982E+00 1.1583950197E+01 1.3015130696E+01 - 4.4198402081E+00 1.1702655703E+01 4.3377789244E+00 - 4.4344191141E+00 1.1654275279E+01 8.6447016704E+00 - 8.8981682352E+00 1.5094983815E-02 3.2438206065E-02 - 8.8516628102E+00 1.7476536158E+01 4.3198763063E+00 -:V: - -1.4824531393E-04 6.8906027803E-04 4.3629621366E-04 - -1.0300428975E-04 -1.5786484339E-04 5.1477751547E-04 - 5.5528981303E-04 -4.5474831115E-04 -3.0152792181E-04 - -4.1514524163E-04 -1.3659424090E-04 -4.4793170630E-04 - 1.9996253518E-04 4.0538936339E-04 -3.3573355198E-05 - -2.5846188285E-04 3.6729292419E-04 -6.1523114419E-05 - -8.8067866592E-04 -5.9348494282E-04 2.6421622983E-04 - -4.6738269551E-05 1.3163593376E-04 3.9357705115E-04 - 3.6926938524E-04 -4.7202665347E-04 1.4855089431E-04 - -3.0563189247E-04 -2.7116098733E-05 -6.1416254817E-04 - 1.6139730063E-04 1.9651649714E-05 -3.0590492389E-04 - 1.8828185464E-04 -4.7569252053E-04 4.2783776821E-04 - 6.3541486839E-04 -4.7192286427E-05 3.7454925545E-04 - 8.7366092851E-04 3.4906662658E-04 -4.8111392553E-05 - -6.1196043774E-04 5.6900630813E-04 -2.9499448912E-04 - 1.4710029990E-04 -8.3918178937E-04 -6.2689552912E-05 - -2.3147888272E-04 5.9740890409E-04 -2.8290457358E-05 - -5.5924591509E-05 1.2613710370E-05 -4.2701029401E-04 - 1.9961941764E-04 1.8221933875E-04 4.2929259478E-04 - -3.6384831586E-04 -4.1199211262E-05 -2.8122137173E-04 -:F: - -8.6754400131E-02 4.1566282537E-03 -5.1231952445E-03 - -8.3959726100E-02 -1.5318573937E-03 -6.8039542574E-03 - -5.4132104221E-02 -1.9255184634E-03 1.4561892596E-02 - -4.6275719308E-02 -1.5182101909E-03 5.8978385361E-03 - -4.7165343508E-02 3.5998042099E-04 -2.7353134765E-03 - -5.3548901364E-02 -6.8487550420E-04 -4.0532757832E-03 - -4.7983225569E-02 -1.0885980044E-03 -1.7581624478E-04 - -5.4240439599E-02 2.1399397597E-03 -2.1441332766E-03 - -5.1732842457E-02 1.9153951361E-04 4.3208449025E-03 - 8.4100800940E-02 2.1862784956E-04 1.0589265381E-02 - 8.3602451392E-02 7.8695714385E-04 3.0743423536E-03 - 5.7239869568E-02 -1.8494853867E-03 -1.6333909025E-02 - 4.6229186032E-02 -1.4209909458E-03 -1.0154299665E-02 - 5.0458194811E-02 1.0419845382E-06 3.3651808580E-03 - 5.0052669589E-02 -1.2227979610E-04 7.6367916452E-03 - 4.6585271845E-02 -3.0654306934E-03 -4.3401984106E-03 - 5.4219610626E-02 3.2005216334E-03 -4.2522988751E-03 - 5.3460215434E-02 2.2158000845E-03 6.6999958837E-03 - 1.1325293389E-03 -6.2265841420E-04 4.0881171575E-02 - -1.2880973186E-03 5.5886814906E-04 -4.0910929472E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020216180E+01 -:STRIO: - -1.6157787223E+00 1.6429640019E-01 -1.9760482005E-01 - 1.6429640019E-01 -1.6077544830E+00 5.6578448304E-02 - -1.9760482005E-01 5.6578448304E-02 -1.0434203849E+00 -:STRESS: - -1.0994396450E+01 -3.9082458307E-02 1.5678530036E-01 - -3.9082458307E-02 1.8666440459E+00 -7.6244860004E-02 - 1.5678530036E-01 -7.6244860004E-02 -2.2114533463E+01 -:PRESIO: 1.4223178634E+00 -:PRES: 1.0414095289E+01 -:PRESIG: 1.4983036254E+00 -:MIND: -Al - Al: 4.2538125763E+00 -C - C: 1.7980161738E+01 -Al - C: 4.4153200291E+00 -:MDSTEP: 4 -:MDTM: 2.07 -:TWIST: 0 -:TEL: 2400 -:TIO: 2485.92698922937 -:TEN: -2.6304873134E+00 -:KEN: 1.1218258828E-02 -:KENIG: 1.1808693503E-02 -:FEN: -2.6417055722E+00 -:UEN: -2.6372282327E+00 -:TSEN: -4.4773395097E-03 -:NPT_NP_HAMIL: -1.0304382552E-04 -:R: - 1.3304151253E+01 8.5529373786E-02 5.4030607783E-02 - 1.3309808469E+01 1.7460360853E+01 4.4037858164E+00 - 6.8851821280E-02 1.7423534330E+01 8.6429935899E+00 - 1.3271197463E+01 5.8096799609E+00 1.2964791443E+01 - 2.4902225513E-02 5.8769295216E+00 4.3358378643E+00 - 1.3290462614E+01 5.8722166780E+00 8.6724372202E+00 - 1.3213431624E+01 1.1579677011E+01 3.2785606151E-02 - 1.3316754453E+01 1.1669663968E+01 4.3888232541E+00 - 4.5778067276E-02 1.1594732696E+01 8.6986373252E+00 - 4.4029322592E+00 1.7476607152E+01 1.2944245239E+01 - 4.4608456250E+00 2.4502882896E-03 4.3021759921E+00 - 4.4642732892E+00 1.7420936605E+01 8.7329136203E+00 - 4.5195386871E+00 5.8207693935E+00 4.6296545944E-02 - 4.5491587811E+00 5.8699384732E+00 4.3341420318E+00 - 4.3649464384E+00 5.8972431098E+00 8.6436812130E+00 - 4.4589852120E+00 1.1549173385E+01 1.3012394112E+01 - 4.4121596327E+00 1.1727448485E+01 4.3364638253E+00 - 4.4339651021E+00 1.1654873355E+01 8.6272953662E+00 - 8.9065037561E+00 2.2574708024E-02 5.3363340397E-02 - 8.8365301217E+00 1.7474877631E+01 4.3050677148E+00 -:V: - -2.2087808032E-04 6.9165310502E-04 4.3142796581E-04 - -1.7334993504E-04 -1.5894537949E-04 5.0839626055E-04 - 5.0912643102E-04 -4.5577307187E-04 -2.8891172571E-04 - -4.5345111933E-04 -1.3769099304E-04 -4.4239805003E-04 - 1.6010963745E-04 4.0516415344E-04 -3.5825825448E-05 - -3.0307704182E-04 3.6624017603E-04 -6.4845581320E-05 - -9.1981226392E-04 -5.9362666372E-04 2.6372490771E-04 - -9.2209380738E-05 1.3326104480E-04 3.9126514049E-04 - 3.2536205826E-04 -4.7125178013E-04 1.5198475164E-04 - -2.3463620447E-04 -2.6897295605E-05 -6.0447443364E-04 - 2.3136706634E-04 2.0286691729E-05 -3.0292621066E-04 - 2.3608668299E-04 -4.7662620808E-04 4.1356973650E-04 - 6.7339512266E-04 -4.8323736352E-05 3.6553799764E-04 - 9.1488125912E-04 3.4861338067E-04 -4.5223914374E-05 - -5.6914779445E-04 5.6816340824E-04 -2.8820004046E-04 - 1.8601474510E-04 -8.4066331342E-04 -6.6251358356E-05 - -1.8566330784E-04 5.9931836576E-04 -3.1823227632E-05 - -1.0974876368E-05 1.4457344816E-05 -4.2083048787E-04 - 2.0149536967E-04 1.8080811158E-04 5.0582508927E-04 - -3.6580397290E-04 -4.0091736604E-05 -3.5800261594E-04 -:F: - -8.7078506458E-02 6.1448343006E-03 -7.3167126701E-03 - -8.3210469727E-02 -2.2325250953E-03 -1.0554587513E-02 - -5.4187786219E-02 -2.8244363565E-03 2.1719025272E-02 - -4.3000834579E-02 -2.3392487722E-03 9.4856427926E-03 - -4.4154318558E-02 4.2867164458E-04 -4.6203396793E-03 - -5.4729897822E-02 -2.7183988630E-04 -6.0862650199E-03 - -4.5560198853E-02 -1.5936696892E-03 2.7122362026E-04 - -5.4445535411E-02 3.2951785537E-03 -3.7721206734E-03 - -5.1983643767E-02 -5.3121377570E-04 6.5147324682E-03 - 8.3112818089E-02 4.1280338438E-04 1.6322186973E-02 - 8.2516617026E-02 1.1384205977E-03 4.3204432656E-03 - 5.8928296566E-02 -2.8304668219E-03 -2.4566413403E-02 - 4.2851662050E-02 -2.1935625992E-03 -1.4585556528E-02 - 4.9093693749E-02 -7.5581267018E-05 4.6143505245E-03 - 4.9551969641E-02 5.6298611709E-04 1.1086675501E-02 - 4.3506695775E-02 -4.3667407107E-03 -5.6275949846E-03 - 5.4373277239E-02 4.8981334561E-03 -7.1198907206E-03 - 5.4589234859E-02 2.4808643325E-03 9.9562905897E-03 - 1.6279860479E-03 -9.3942773588E-04 4.2755128573E-02 - -1.8010596473E-03 8.3682032333E-04 -4.2796218386E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020220304E+01 -:STRIO: - -1.6928338939E+00 1.6421678063E-01 -1.4071962974E-01 - 1.6421678063E-01 -1.6117441135E+00 5.2809601910E-02 - -1.4071962974E-01 5.2809601910E-02 -1.0381789292E+00 -:STRESS: - -1.0709873372E+01 -5.9903246303E-02 2.3533225395E-01 - -5.9903246303E-02 1.8333683130E+00 -1.1658226232E-01 - 2.3533225395E-01 -1.1658226232E-01 -2.2133610691E+01 -:PRESIO: 1.4475856455E+00 -:PRES: 1.0336705250E+01 -:PRESIG: 1.5277468432E+00 -:MIND: -Al - Al: 4.2121462389E+00 -C - C: 1.7962871812E+01 -Al - C: 4.3980981389E+00 -:MDSTEP: 5 -:MDTM: 2.08 -:TWIST: 0 -:TEL: 2400 -:TIO: 2550.16939500551 -:TEN: -2.6305562897E+00 -:KEN: 1.1508165949E-02 -:KENIG: 1.2113858893E-02 -:FEN: -2.6420644556E+00 -:UEN: -2.6375936765E+00 -:TSEN: -4.4707791544E-03 -:NPT_NP_HAMIL: -1.4565676987E-04 -:R: - 1.3292012446E+01 1.1429297163E-01 7.1585463326E-02 - 1.3299765758E+01 1.7453722368E+01 4.4244073068E+00 - 8.7987681188E-02 1.7404622708E+01 8.6318249777E+00 - 1.3250987721E+01 5.8039151216E+00 1.2946864525E+01 - 2.9979322536E-02 5.8936689592E+00 4.3342005561E+00 - 1.3276053132E+01 5.8873250874E+00 8.6695529946E+00 - 1.3173882397E+01 1.1555117705E+01 4.3681196307E-02 - 1.3311059136E+01 1.1675279113E+01 4.4048450683E+00 - 5.7404886807E-02 1.1575261703E+01 8.7051407461E+00 - 4.3961305298E+00 1.7475511194E+01 1.2919865247E+01 - 4.4732591209E+00 3.3271911483E-03 4.2898233804E+00 - 4.4760631787E+00 1.7401163989E+01 8.7491364912E+00 - 4.5488222104E+00 5.8186985544E+00 6.0879358606E-02 - 4.5886270621E+00 5.8843260846E+00 4.3324371927E+00 - 4.3431721420E+00 5.9207155706E+00 8.6321730762E+00 - 4.4681731366E+00 1.1514320564E+01 1.3009469610E+01 - 4.4063822778E+00 1.1752357389E+01 4.3349050137E+00 - 4.4354061147E+00 1.1655556209E+01 8.6102732180E+00 - 8.9149480685E+00 2.9964973248E-02 7.7575462634E-02 - 8.8212899087E+00 1.7473287928E+01 4.2869561239E+00 -:V: - -2.9317638330E-04 6.9469823970E-04 4.2398421137E-04 - -2.4255148029E-04 -1.6033265687E-04 4.9800507329E-04 - 4.6216917170E-04 -4.5675335941E-04 -2.6983264638E-04 - -4.8810558357E-04 -1.3923236249E-04 -4.3310339753E-04 - 1.2262201631E-04 4.0429079347E-04 -3.9588600248E-05 - -3.4801771802E-04 3.6489821320E-04 -6.9748492591E-05 - -9.5519267922E-04 -5.9315621609E-04 2.6314989165E-04 - -1.3755326206E-04 1.3561694321E-04 3.8691387386E-04 - 2.8081087435E-04 -4.7026329870E-04 1.5698161869E-04 - -1.6427532535E-04 -2.6469547438E-05 -5.8895781340E-04 - 2.9981067715E-04 2.1178952491E-05 -2.9838420164E-04 - 2.8474933950E-04 -4.7754811020E-04 3.9172536498E-04 - 7.0725547535E-04 -5.0014893971E-05 3.5220352894E-04 - 9.5323768177E-04 3.4748950287E-04 -4.1219591090E-05 - -5.2589267230E-04 5.6690672958E-04 -2.7803284774E-04 - 2.2190669968E-04 -8.4176512228E-04 -7.0765635613E-05 - -1.3953464094E-04 6.0159968533E-04 -3.7692758701E-05 - 3.4803326866E-05 1.6492283623E-05 -4.1120705307E-04 - 2.0394698105E-04 1.7848964057E-04 5.8477048277E-04 - -3.6808153080E-04 -3.8394501948E-05 -4.3747506024E-04 -:F: - -8.6758918156E-02 8.0452320894E-03 -9.4193800173E-03 - -8.2135081692E-02 -2.8703258775E-03 -1.4369263641E-02 - -5.3770459519E-02 -3.6812663486E-03 2.8711193028E-02 - -3.9826649498E-02 -3.1522827362E-03 1.3028642383E-02 - -4.1084059319E-02 4.7402828689E-04 -6.4327164144E-03 - -5.5573488710E-02 1.0906546092E-04 -8.0860844672E-03 - -4.3200946821E-02 -2.1175323973E-03 6.8372558912E-04 - -5.4313412059E-02 4.4549963488E-03 -5.3486102793E-03 - -5.1868988263E-02 -1.2547509789E-03 8.6776140536E-03 - 8.1501146597E-02 6.7414060824E-04 2.2146045474E-02 - 8.0969153208E-02 1.4695326469E-03 5.5045341070E-03 - 6.0198481568E-02 -3.8443455942E-03 -3.2719515782E-02 - 3.9530689476E-02 -2.9522787887E-03 -1.8899194411E-02 - 4.7662656746E-02 -1.4782468202E-04 5.9383096411E-03 - 4.8758664437E-02 1.2071360869E-03 1.4252757071E-02 - 4.0520233718E-02 -5.5554635907E-03 -6.7116877498E-03 - 5.4166568269E-02 6.5841527177E-03 -1.0018693103E-02 - 5.5363085003E-02 2.7068849236E-03 1.3095641938E-02 - 2.0131341608E-03 -1.2617948666E-03 4.4951625126E-02 - -2.1518091448E-03 1.1126966912E-03 -4.4984942547E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020225817E+01 -:STRIO: - -1.8016283544E+00 1.6449577412E-01 -8.3704831364E-02 - 1.6449577412E-01 -1.6148549997E+00 4.9612401551E-02 - -8.3704831364E-02 4.9612401551E-02 -1.0229782697E+00 -:STRESS: - -1.0333983854E+01 -8.1203371988E-02 3.0928269909E-01 - -8.1203371988E-02 1.7864158201E+00 -1.5639254354E-01 - 3.0928269909E-01 -1.5639254354E-01 -2.2160050022E+01 -:PRESIO: 1.4798205413E+00 -:PRES: 1.0235872685E+01 -:PRESIG: 1.5672268776E+00 -:MIND: -Al - Al: 4.1721571266E+00 -C - C: 1.7944279677E+01 -Al - C: 4.3778807267E+00 -:MDSTEP: 6 -:MDTM: 2.07 -:TWIST: 0 -:TEL: 2400 -:TIO: 2626.75477224939 -:TEN: -2.6306695093E+00 -:KEN: 1.1853773277E-02 -:KENIG: 1.2477656081E-02 -:FEN: -2.6425232826E+00 -:UEN: -2.6380635383E+00 -:TSEN: -4.4597443465E-03 -:NPT_NP_HAMIL: -1.8775947526E-04 -:R: - 1.3276921051E+01 1.4320856685E-01 8.8736601705E-02 - 1.3286921432E+01 1.7447013685E+01 4.4444405418E+00 - 1.0517613392E-01 1.7385666879E+01 8.6217013415E+00 - 1.3229487099E+01 5.7980664652E+00 1.2929469462E+01 - 3.3610535802E-02 5.9103510515E+00 4.3323480574E+00 - 1.3259781603E+01 5.9023706940E+00 8.6664022660E+00 - 1.3133010605E+01 1.1530593260E+01 5.4552469876E-02 - 1.3303507028E+01 1.1681023872E+01 4.4206114473E+00 - 6.7183274564E-02 1.1555833042E+01 8.7119171414E+00 - 4.3921826842E+00 1.7474443425E+01 1.2896361447E+01 - 4.4884233872E+00 4.2511469453E-03 4.2777164006E+00 - 4.4898869101E+00 1.7381345307E+01 8.7641551556E+00 - 4.5793463700E+00 5.8165345487E+00 7.4743086028E-02 - 4.6295728579E+00 5.8986451687E+00 4.3309461003E+00 - 4.3231832281E+00 5.9441264153E+00 8.6212104456E+00 - 4.4787245441E+00 1.1479428847E+01 1.3006326883E+01 - 4.4025071845E+00 1.1777384652E+01 4.3330064162E+00 - 4.4387590358E+00 1.1656329844E+01 8.5937807785E+00 - 8.9235118595E+00 3.7224458303E-02 1.0517970857E-01 - 8.8059493726E+00 1.7471791837E+01 4.2654234172E+00 -:V: - -3.6398612319E-04 6.9740902683E-04 4.1366370157E-04 - -3.0978955442E-04 -1.6180528277E-04 4.8312048695E-04 - 4.1456459738E-04 -4.5719158723E-04 -2.4428062598E-04 - -5.1856886407E-04 -1.4106248802E-04 -4.1971401157E-04 - 8.7580452402E-05 4.0235179908E-04 -4.4735663378E-05 - -3.9244951895E-04 3.6288175157E-04 -7.6103050173E-05 - -9.8577797191E-04 -5.9149980991E-04 2.6220135007E-04 - -1.8214765247E-04 1.3855660861E-04 3.8020935712E-04 - 2.3584283283E-04 -4.6859569336E-04 1.6332666091E-04 - -9.5217240795E-05 -2.5753293770E-05 -5.6704895892E-04 - 3.6574368094E-04 2.2284691303E-05 -2.9206071796E-04 - 3.3341160578E-04 -4.7800251298E-04 3.6211961414E-04 - 7.3620564454E-04 -5.2193188108E-05 3.3437548063E-04 - 9.8756284844E-04 3.4535891261E-04 -3.6018958174E-05 - -4.8210831894E-04 5.6464113297E-04 -2.6451615592E-04 - 2.5448712892E-04 -8.4154580856E-04 -7.5965756169E-05 - -9.3462540919E-05 6.0362719645E-04 -4.5847517376E-05 - 8.0868383398E-05 1.8659128254E-05 -3.9788814713E-04 - 2.0654823318E-04 1.7508995993E-04 6.6577987927E-04 - -3.6999509481E-04 -3.6083892702E-05 -5.1939776275E-04 -:F: - -8.5811397976E-02 9.8347338631E-03 -1.1430167588E-02 - -8.0791237672E-02 -3.4301308324E-03 -1.8186733491E-02 - -5.2860298676E-02 -4.4896860287E-03 3.5435553536E-02 - -3.6809497442E-02 -3.9619583715E-03 1.6471595690E-02 - -3.7981434232E-02 5.0352440027E-04 -8.1579360638E-03 - -5.6067729611E-02 4.5002373383E-04 -1.0024301018E-02 - -4.0932820430E-02 -2.6481446922E-03 1.0763811955E-03 - -5.3847699118E-02 5.6060871434E-03 -6.8596636596E-03 - -5.1375189134E-02 -1.9628973530E-03 1.0761589736E-02 - 7.9290454417E-02 1.0111261894E-03 2.7970445534E-02 - 7.8996493320E-02 1.7893498677E-03 6.6427424827E-03 - 6.1028232519E-02 -4.8865160171E-03 -4.0682280229E-02 - 3.6324856523E-02 -3.6973040375E-03 -2.3032767507E-02 - 4.6187330917E-02 -2.1161185923E-04 7.3022326862E-03 - 4.7662342265E-02 1.8014224227E-03 1.7119540151E-02 - 3.7660937490E-02 -6.6336131959E-03 -7.5818839940E-03 - 5.3603814142E-02 8.2350162114E-03 -1.2897695074E-02 - 5.5762265588E-02 2.8925858585E-03 1.6074892973E-02 - 2.2412404789E-03 -1.5886608707E-03 4.7516659879E-02 - -2.2806633694E-03 1.3866535679E-03 -4.7518205240E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020232748E+01 -:STRIO: - -1.9352831334E+00 1.6480198975E-01 -2.7899593844E-02 - 1.6480198975E-01 -1.6136966495E+00 4.7024219720E-02 - -2.7899593844E-02 4.7024219720E-02 -9.9875988649E-01 -:STRESS: - -9.8757096655E+00 -1.0266768550E-01 3.7561760663E-01 - -1.0266768550E-01 1.7279924742E+00 -1.9344905135E-01 - 3.7561760663E-01 -1.9344905135E-01 -2.2185634781E+01 -:PRESIO: 1.5159132231E+00 -:PRES: 1.0111117324E+01 -:PRESIG: 1.6142921708E+00 -:MIND: -Al - Al: 4.1344095363E+00 -C - C: 1.7924441089E+01 -Al - C: 4.3547301401E+00 -:MDSTEP: 7 -:MDTM: 2.07 -:TWIST: 0 -:TEL: 2400 -:TIO: 2710.31337706398 -:TEN: -2.6308488731E+00 -:KEN: 1.2230848734E-02 -:KENIG: 1.2874577615E-02 -:FEN: -2.6430797218E+00 -:UEN: -2.6386361657E+00 -:TSEN: -4.4435561771E-03 -:NPT_NP_HAMIL: -2.3656497719E-04 -:R: - 1.3258978054E+01 1.7224210775E-01 1.0536070488E-01 - 1.3271381848E+01 1.7440237924E+01 4.4636914512E+00 - 1.2040449882E-01 1.7366701425E+01 8.6128819283E+00 - 1.3206878715E+01 5.7921257311E+00 1.2912779172E+01 - 3.5900367241E-02 5.9269223866E+00 4.3302281769E+00 - 1.3241696142E+01 5.9173162665E+00 8.6629300924E+00 - 1.3091037286E+01 1.1506165660E+01 6.5377454151E-02 - 1.3294150771E+01 1.1686918364E+01 4.4360199939E+00 - 7.5109865170E-02 1.1536485772E+01 8.7190146537E+00 - 4.3910072113E+00 1.7473418827E+01 1.2874007004E+01 - 4.5062030202E+00 5.2298836147E-03 4.2659326540E+00 - 4.5057149250E+00 1.7361509908E+01 8.7776525774E+00 - 4.6108922041E+00 5.8142593082E+00 8.7703788545E-02 - 4.6718013241E+00 5.9128469199E+00 4.3297194967E+00 - 4.3049961613E+00 5.9674196895E+00 8.6109250749E+00 - 4.4904972834E+00 1.1444575802E+01 1.3002947622E+01 - 4.4005156037E+00 1.1802504415E+01 4.3306768798E+00 - 4.4440145798E+00 1.1657197566E+01 8.5779719526E+00 - 8.9321839661E+00 4.4304751923E-02 1.3626325600E-01 - 8.7905495246E+00 1.7470414964E+01 4.2403651544E+00 -:V: - -4.3192667936E-04 6.9890003222E-04 4.0017668803E-04 - -3.7407134562E-04 -1.6310720257E-04 4.6334195860E-04 - 3.6657963149E-04 -4.5653943051E-04 -2.1243618671E-04 - -5.4423264245E-04 -1.4300629777E-04 -4.0197207362E-04 - 5.5121187988E-05 3.9890782510E-04 -5.1097367577E-05 - -4.3535610274E-04 3.5977220785E-04 -8.3717274484E-05 - -1.0103884254E-03 -5.8802507939E-04 2.6057990284E-04 - -2.2522532288E-04 1.4189316466E-04 3.7084835542E-04 - 1.9081015468E-04 -4.6573056779E-04 1.7071718608E-04 - -2.8296171073E-05 -2.4664294700E-05 -5.3831996173E-04 - 4.2799416478E-04 2.3560305375E-05 -2.8372664718E-04 - 3.8101450168E-04 -4.7748089082E-04 3.2477601739E-04 - 7.5937635555E-04 -5.4769951422E-05 3.1199093988E-04 - 1.0165303820E-03 3.4186682159E-04 -2.9594242762E-05 - -4.3780197635E-04 5.6071941337E-04 -2.4772494167E-04 - 2.8339526042E-04 -8.3898806444E-04 -8.1548062080E-05 - -4.7941652196E-05 6.0468692369E-04 -5.6144248967E-05 - 1.2651229442E-04 2.0887962657E-05 -3.8068601088E-04 - 2.0875633519E-04 1.7043795849E-04 7.4824648382E-04 - -3.7070760054E-04 -3.3144310643E-05 -6.0327273115E-04 -:F: - -8.4268512304E-02 1.1488725931E-02 -1.3354236159E-02 - -7.9247056000E-02 -3.9050710711E-03 -2.1920670459E-02 - -5.1456609152E-02 -5.2433730373E-03 4.1782870179E-02 - -3.3985976704E-02 -4.7654702094E-03 1.9743966572E-02 - -3.4886267515E-02 5.2653357079E-04 -9.7786543420E-03 - -5.6208924545E-02 7.4495926056E-04 -1.1863037022E-02 - -3.8794128059E-02 -3.1725988706E-03 1.4455724125E-03 - -5.3055566129E-02 6.7326467395E-03 -8.2715779891E-03 - -5.0497657782E-02 -2.6389808329E-03 1.2718951486E-02 - 7.6520916130E-02 1.4171254348E-03 3.3674637914E-02 - 7.6650652765E-02 2.1124511320E-03 7.7433624387E-03 - 6.1412772223E-02 -5.9479625516E-03 -4.8320778760E-02 - 3.3273118249E-02 -4.4248247528E-03 -2.6916580014E-02 - 4.4701441345E-02 -2.6607712861E-04 8.6689972974E-03 - 4.6260767002E-02 2.3326270506E-03 1.9670082111E-02 - 3.4964080845E-02 -7.6013400310E-03 -8.2374053894E-03 - 5.2698103320E-02 9.8272237968E-03 -1.5700478350E-02 - 5.5778857909E-02 3.0409620522E-03 1.8853664775E-02 - 2.2690723664E-03 -1.9143448887E-03 5.0487018641E-02 - -2.1290839636E-03 1.6567884059E-03 -5.0425705344E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020241146E+01 -:STRIO: - -2.0844191353E+00 1.6475617731E-01 2.5076283044E-02 - 1.6475617731E-01 -1.6045547928E+00 4.5071066343E-02 - 2.5076283044E-02 4.5071066343E-02 -9.6738800838E-01 -:STRESS: - -9.3485488996E+00 -1.2391394395E-01 4.3153943828E-01 - -1.2391394395E-01 1.6609805036E+00 -2.2431201032E-01 - 4.3153943828E-01 -2.2431201032E-01 -2.2201341571E+01 -:PRESIO: 1.5521206455E+00 -:PRES: 9.9629699891E+00 -:PRESIG: 1.6656426740E+00 -:MIND: -Al - Al: 4.0994879016E+00 -C - C: 1.7903436258E+01 -Al - C: 4.3287954461E+00 -:MDSTEP: 8 -:MDTM: 2.07 -:TWIST: 0 -:TEL: 2400 -:TIO: 2794.34188174335 -:TEN: -2.6311182385E+00 -:KEN: 1.2610044711E-02 -:KENIG: 1.3273731275E-02 -:FEN: -2.6437282832E+00 -:UEN: -2.6393065980E+00 -:TSEN: -4.4216851788E-03 -:NPT_NP_HAMIL: -2.8998545258E-04 -:R: - 1.3238344141E+01 2.0132231716E-01 1.2132394330E-01 - 1.3253295627E+01 1.7433409052E+01 4.4819548984E+00 - 1.3367436777E-01 1.7347783496E+01 8.6056111973E+00 - 1.3183370195E+01 5.7860921485E+00 1.2896972619E+01 - 3.6959151118E-02 5.9433123131E+00 4.3277970399E+00 - 1.3221889451E+01 5.9321075448E+00 8.6590915914E+00 - 1.3048231182E+01 1.1481922803E+01 7.6121953651E-02 - 1.3283076937E+01 1.1692974124E+01 4.4509581990E+00 - 8.1198977715E-02 1.1517280469E+01 8.7264665635E+00 - 4.3924856348E+00 1.7472455455E+01 1.2853085070E+01 - 4.5264127443E+00 6.2697062956E-03 4.2545584773E+00 - 4.5234708741E+00 1.7341708205E+01 8.7893216467E+00 - 4.6432059461E+00 5.8118588260E+00 9.9579881152E-02 - 4.7150632874E+00 5.9268684572E+00 4.3288072672E+00 - 4.2886239820E+00 5.9905129058E+00 8.6014432160E+00 - 4.5033343957E+00 1.1409880277E+01 1.2999326537E+01 - 4.4003659329E+00 1.1827660663E+01 4.3278343267E+00 - 4.4511310317E+00 1.1658159743E+01 8.5630049871E+00 - 8.9409274722E+00 5.1151425513E-02 1.7088493901E-01 - 8.7751701491E+00 1.7469183064E+01 4.2117015017E+00 -:V: - -4.9546330718E-04 6.9827649570E-04 3.8330872490E-04 - -4.3428788676E-04 -1.6397546628E-04 4.3846159051E-04 - 3.1863723729E-04 -4.5425893798E-04 -1.7474340533E-04 - -5.6448860292E-04 -1.4487890691E-04 -3.7978516521E-04 - 2.5423609763E-05 3.9355632748E-04 -5.8456101498E-05 - -4.7559997554E-04 3.5516945027E-04 -9.2329321185E-05 - -1.0278638588E-03 -5.8212158228E-04 2.5799664919E-04 - -2.6590586153E-04 1.4541142334E-04 3.5861610006E-04 - 1.4621229544E-04 -4.6115939014E-04 1.7877596579E-04 - 3.5500032190E-05 -2.3132579220E-05 -5.0261542605E-04 - 4.8527763821E-04 2.4968311870E-05 -2.7319596208E-04 - 4.2635737982E-04 -4.7548020684E-04 2.8003768793E-04 - 7.7592036028E-04 -5.7640586787E-05 2.8516815090E-04 - 1.0388099925E-03 3.3668636236E-04 -2.1983953539E-05 - -3.9313018190E-04 5.5451630116E-04 -2.2783716608E-04 - 3.0824584878E-04 -8.3311193373E-04 -8.7188310165E-05 - -3.5939080375E-06 6.0405400462E-04 -6.8335067933E-05 - 1.7088085754E-04 2.3103868160E-05 -3.5954541273E-04 - 2.0994982179E-04 1.6440291659E-04 8.3133633811E-04 - -3.6929088919E-04 -2.9580485838E-05 -6.8835188003E-04 -:F: - -8.2177389200E-02 1.2989361634E-02 -1.5182445407E-02 - -7.7561195856E-02 -4.2902765975E-03 -2.5481299919E-02 - -4.9586775670E-02 -5.9356314546E-03 4.7645239558E-02 - -3.1370332232E-02 -5.5576506064E-03 2.2767309353E-02 - -3.1849134399E-02 5.4927055138E-04 -1.1280893300E-02 - -5.6001907174E-02 9.8791876082E-04 -1.3553283209E-02 - -3.6831118588E-02 -3.6847381145E-03 1.7807820673E-03 - -5.1950596059E-02 7.8202585541E-03 -9.5446576077E-03 - -4.9242987055E-02 -3.2645071662E-03 1.4508397869E-02 - 7.3257506136E-02 1.8811003966E-03 3.9120139306E-02 - 7.3976705992E-02 2.4516473559E-03 8.7989077781E-03 - 6.1362532244E-02 -7.0142751665E-03 -5.5484368539E-02 - 3.0400643095E-02 -5.1245294524E-03 -3.0486613816E-02 - 4.3246363652E-02 -3.0619656475E-04 1.0004132425E-02 - 4.4558603283E-02 2.7855796579E-03 2.1891525329E-02 - 3.2463058063E-02 -8.4571150954E-03 -8.6931930281E-03 - 5.1475157602E-02 1.1332251043E-02 -1.8358856925E-02 - 5.5420519725E-02 3.1543814805E-03 2.1390937932E-02 - 2.0534268569E-03 -2.2372875431E-03 5.3912359809E-02 - -1.6430804162E-03 1.9204383279E-03 -5.3754119674E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020251092E+01 -:STRIO: - -2.2375485564E+00 1.6396959669E-01 7.3419922687E-02 - 1.6396959669E-01 -1.5838867545E+00 4.3757143589E-02 - 7.3419922687E-02 4.3757143589E-02 -9.3182890167E-01 -:STRESS: - -8.7704091516E+00 -1.4429042220E-01 4.7537474469E-01 - -1.4429042220E-01 1.5881941742E+00 -2.4419036917E-01 - 4.7537474469E-01 -2.4419036917E-01 -2.2195898205E+01 -:PRESIO: 1.5844214042E+00 -:PRES: 9.7927043942E+00 -:PRESIG: 1.7172816870E+00 -:MIND: -Al - Al: 4.0679755580E+00 -C - C: 1.7881372994E+01 -Al - C: 4.3003252914E+00 -:MDSTEP: 9 -:MDTM: 2.08 -:TWIST: 0 -:TEL: 2400 -:TIO: 2871.81316912992 -:TEN: -2.6315143098E+00 -:KEN: 1.2959649892E-02 -:KENIG: 1.3641736728E-02 -:FEN: -2.6444739597E+00 -:UEN: -2.6400799928E+00 -:TSEN: -4.3939669368E-03 -:NPT_NP_HAMIL: -3.4288997718E-04 -:R: - 1.3215243114E+01 2.3034279460E-01 1.3648696947E-01 - 1.3232856693E+01 1.7426551556E+01 4.4990244578E+00 - 1.4500756473E-01 1.7328990912E+01 8.6001070817E+00 - 1.3159192146E+01 5.7799724992E+00 1.2882226275E+01 - 3.6904037842E-02 5.9594356611E+00 4.3250208497E+00 - 1.3200501547E+01 5.9466751764E+00 8.6548550028E+00 - 1.3004903840E+01 1.1457975457E+01 8.6740580495E-02 - 1.3270409132E+01 1.1699193387E+01 4.4653085700E+00 - 8.5488313397E-02 1.1498297390E+01 8.7342889392E+00 - 4.3964580110E+00 1.7471573563E+01 1.2833874890E+01 - 4.5488149067E+00 7.3757427037E-03 4.2436856431E+00 - 4.5430281335E+00 1.7322010140E+01 8.7988803299E+00 - 4.6760025000E+00 5.8093238950E+00 1.1020055380E-01 - 4.7590592029E+00 5.9406352434E+00 4.3282556320E+00 - 4.2740695642E+00 6.0132997076E+00 8.5928806794E+00 - 4.5170644902E+00 1.1375498176E+01 1.2995471356E+01 - 4.4019893649E+00 1.1852768528E+01 4.3244104384E+00 - 4.4600297304E+00 1.1659213657E+01 8.5490356532E+00 - 8.9496773474E+00 5.7705982711E-02 2.0906920825E-01 - 8.7599316900E+00 1.7468121004E+01 4.1793843404E+00 -:V: - -5.5303760531E-04 6.9474899419E-04 3.6299960971E-04 - -4.8930720703E-04 -1.6416814588E-04 4.0854880030E-04 - 2.7131625282E-04 -4.4989365409E-04 -1.3195208862E-04 - -5.7882145579E-04 -1.4650414319E-04 -3.5330230412E-04 - -1.3194094988E-06 3.8599226487E-04 -6.6554306299E-05 - -5.1202549362E-04 3.4874848035E-04 -1.0160869082E-04 - -1.0372547415E-03 -5.7329843917E-04 2.5420784872E-04 - -3.0326671097E-04 1.4888888603E-04 3.4345220725E-04 - 1.0268651359E-04 -4.5445409792E-04 1.8708096426E-04 - 9.5098517796E-05 -2.1112459257E-05 -4.6016541491E-04 - 5.3630681386E-04 2.6478464516E-05 -2.6038605481E-04 - 4.6819995730E-04 -4.7157084246E-04 2.2864675001E-04 - 7.8514810331E-04 -6.0686138964E-05 2.5425632413E-04 - 1.0532603449E-03 3.2957627566E-04 -1.3298575138E-05 - -3.4843214203E-04 5.4551506585E-04 -2.0517046797E-04 - 3.2869787662E-04 -8.2310603587E-04 -9.2570508843E-05 - 3.8864892812E-05 6.0108122392E-04 -8.2060174362E-05 - 2.1303446899E-04 2.5230641901E-05 -3.3460814450E-04 - 2.0947164111E-04 1.5691582022E-04 9.1412612988E-04 - -3.6480806321E-04 -2.5425670525E-05 -7.7376141839E-04 -:F: - -7.9612753745E-02 1.4316986109E-02 -1.6907479981E-02 - -7.5767596601E-02 -4.5776017092E-03 -2.8760513062E-02 - -4.7305332940E-02 -6.5583807488E-03 5.2914469990E-02 - -2.8974275266E-02 -6.3189115216E-03 2.5476690019E-02 - -2.8915024313E-02 5.7818978515E-04 -1.2659163464E-02 - -5.5470681792E-02 1.1674568413E-03 -1.5048554652E-02 - -3.5068221523E-02 -4.1824975983E-03 2.0892088395E-03 - -5.0562089969E-02 8.8509845012E-03 -1.0659614966E-02 - -4.7633323428E-02 -3.8178085124E-03 1.6094369355E-02 - 6.9593530343E-02 2.3862791774E-03 4.4149318541E-02 - 7.1009823739E-02 2.8143666891E-03 9.8078026562E-03 - 6.0890288923E-02 -8.0688756770E-03 -6.2013953499E-02 - 2.7733409016E-02 -5.7916729130E-03 -3.3694094776E-02 - 4.1851754748E-02 -3.2350556931E-04 1.1282252376E-02 - 4.2583723832E-02 3.1500866233E-03 2.3780112766E-02 - 3.0176889022E-02 -9.1979601086E-03 -8.9615264509E-03 - 4.9972426732E-02 1.2722835700E-02 -2.0808471699E-02 - 5.4711724653E-02 3.2425157149E-03 2.3644543855E-02 - 1.5545515219E-03 -2.5653534406E-03 5.7908204062E-02 - -7.6882295280E-04 2.1728666582E-03 -5.7633599911E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020262708E+01 -:STRIO: - -2.3820521513E+00 1.6209117399E-01 1.1535853223E-01 - 1.6209117399E-01 -1.5489190736E+00 4.3045837783E-02 - 1.1535853223E-01 4.3045837783E-02 -8.9614447495E-01 -:STRESS: - -8.1610159146E+00 -1.6322785702E-01 5.0675272542E-01 - -1.6322785702E-01 1.5122524405E+00 -2.4829357930E-01 - 5.0675272542E-01 -2.4829357930E-01 -2.2154262961E+01 -:PRESIO: 1.6090385666E+00 -:PRES: 9.6010088116E+00 -:PRESIG: 1.7648906157E+00 -:MIND: -Al - Al: 4.0404248685E+00 -C - C: 1.7858386178E+01 -Al - C: 4.2696748068E+00 -:MDSTEP: 10 -:MDTM: 2.08 -:TWIST: 0 -:TEL: 2400 -:TIO: 2936.1195246646 -:TEN: -2.6320779701E+00 -:KEN: 1.3249845599E-02 -:KENIG: 1.3947205894E-02 -:FEN: -2.6453278157E+00 -:UEN: -2.6409674411E+00 -:TSEN: -4.3603745559E-03 -:NPT_NP_HAMIL: -4.0088287193E-04 -:R: - 1.3189958847E+01 2.5916824507E-01 1.5071209524E-01 - 1.3210303422E+01 1.7419699197E+01 4.5147054422E+00 - 1.5445127781E-01 1.7310417616E+01 8.5965483715E+00 - 1.3134592226E+01 5.7737808556E+00 1.2868703856E+01 - 3.5859003344E-02 5.9751977975E+00 4.3218770039E+00 - 1.3177717523E+01 5.9609385621E+00 8.6502040632E+00 - 1.2961398264E+01 1.1434450664E+01 9.7179907065E-02 - 1.3256307399E+01 1.1705569090E+01 4.4789551281E+00 - 8.8043384340E-02 1.1479632049E+01 8.7424796034E+00 - 4.4027222170E+00 1.7470794315E+01 1.2816634222E+01 - 4.5731219115E+00 8.5521190048E-03 4.2334066562E+00 - 4.5642105634E+00 1.7302500980E+01 8.8060886824E+00 - 4.7089747121E+00 5.8066503285E+00 1.1941520939E-01 - 4.8034500947E+00 5.9540655984E+00 4.3281044978E+00 - 4.2613188958E+00 6.0356559910E+00 8.5853370794E+00 - 4.5315045916E+00 1.1341613293E+01 1.2991402183E+01 - 4.4052875149E+00 1.1877719182E+01 4.3203548373E+00 - 4.4705936816E+00 1.1660353819E+01 8.5362083719E+00 - 8.9583401556E+00 6.3908087803E-02 2.5081055441E-01 - 8.7449941456E+00 1.7467251371E+01 4.1433933132E+00 -:V: - -6.0323908147E-04 6.8772562157E-04 3.3938364514E-04 - -5.3808221979E-04 -1.6348550159E-04 3.7401036325E-04 - 2.2531073551E-04 -4.4312687231E-04 -8.5116745207E-05 - -5.8691173669E-04 -1.4772195742E-04 -3.2293926606E-04 - -2.4932723954E-05 3.7605743832E-04 -7.5113387132E-05 - -5.4358759154E-04 3.4029982477E-04 -1.1117680627E-04 - -1.0379681324E-03 -5.6126105217E-04 2.4906222064E-04 - -3.3644306542E-04 1.5211331966E-04 3.2547328545E-04 - 6.0959593832E-05 -4.4532290355E-04 1.9519979178E-04 - 1.4945317056E-04 -1.8591513529E-05 -4.1164908454E-04 - 5.7992328541E-04 2.8066313262E-05 -2.4534356610E-04 - 5.0537631034E-04 -4.6545496399E-04 1.7176193248E-04 - 7.8666021544E-04 -6.3786693931E-05 2.1984310113E-04 - 1.0590902540E-03 3.2042514874E-04 -3.7125206453E-06 - -3.0420899665E-04 5.3338243300E-04 -1.8018917603E-04 - 3.4451596036E-04 -8.0843497835E-04 -9.7403894256E-05 - 7.8688182362E-05 5.9527964841E-04 -9.6866281931E-05 - 2.5203768776E-04 2.7202308953E-05 -3.0624763445E-04 - 2.0667968882E-04 1.4797154980E-04 9.9587150164E-04 - -3.5638409133E-04 -2.0747945753E-05 -8.5878699418E-04 -:F: - -7.6670441376E-02 1.5463271236E-02 -1.8520509830E-02 - -7.3866829570E-02 -4.7642148669E-03 -3.1640694873E-02 - -4.4688412462E-02 -7.1020654440E-03 5.7481263947E-02 - -2.6812217467E-02 -7.0314198209E-03 2.7824656014E-02 - -2.6112811077E-02 6.1944893493E-04 -1.3908144063E-02 - -5.4650652661E-02 1.2705996458E-03 -1.6316696404E-02 - -3.3512176311E-02 -4.6648647181E-03 2.3906087170E-03 - -4.8930806439E-02 9.8067565930E-03 -1.1609656099E-02 - -4.5708834880E-02 -4.2789792450E-03 1.7442734755E-02 - 6.5638100642E-02 2.9159476837E-03 4.8599121415E-02 - 6.7766640680E-02 3.2056460094E-03 1.0772972108E-02 - 6.0018960507E-02 -9.0928774430E-03 -6.7746306743E-02 - 2.5293466569E-02 -6.4272097356E-03 -3.6490596853E-02 - 4.0528993021E-02 -3.0990001421E-04 1.2463021869E-02 - 4.0383216823E-02 3.4206595927E-03 2.5349248075E-02 - 2.8112558850E-02 -9.8269246549E-03 -9.0561238678E-03 - 4.8234843802E-02 1.3972731279E-02 -2.2992569528E-02 - 5.3691915375E-02 3.3190104573E-03 2.5575450664E-02 - 7.3010169288E-04 -2.9133617260E-03 6.2652177700E-02 - 5.5438428286E-04 2.4177462364E-03 -6.2269957003E-02 -:LATVEC_SCALE: 1.3322568219E+01 1.7479965394E+01 1.3020276164E+01 -:STRIO: - -2.5055609882E+00 1.5886068149E-01 1.4942546132E-01 - 1.5886068149E-01 -1.4981425309E+00 4.2869315305E-02 - 1.4942546132E-01 4.2869315305E-02 -8.6527647663E-01 -:STRESS: - -7.5417281221E+00 -1.8002784995E-01 5.2646366392E-01 - -1.8002784995E-01 1.4353487893E+00 -2.3277842640E-01 - 5.2646366392E-01 -2.3277842640E-01 -2.2061370896E+01 -:PRESIO: 1.6229933319E+00 -:PRES: 9.3892500761E+00 -:PRESIG: 1.8044086211E+00 -:MIND: -Al - Al: 4.0173220757E+00 -C - C: 1.7834631325E+01 -Al - C: 4.2373037390E+00 diff --git a/tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.refout b/tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.refout deleted file mode 100644 index c82317b8..00000000 --- a/tests/Al18C2_NPTNP_onlyc/standard/Al18C2_NPTNP_onlyc.refout +++ /dev/null @@ -1,566 +0,0 @@ -*************************************************************************** -* SPARC (version June 24, 2024) * -* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * -* Distributed under GNU General Public License 3 (GPL) * -* Start time: Sun Aug 11 19:40:37 2024 * -*************************************************************************** - Input parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.020212061 -LATVEC: -1.000000000000000 0.000000000000000 0.000000000000000 -0.000000000000000 1.000000000000000 0.000000000000000 -0.000000000000000 0.000000000000000 1.000000000000000 -FD_GRID: 45 59 44 -FD_ORDER: 12 -BC: P P P -KPOINT_GRID: 1 1 1 -KPOINT_SHIFT: 0 0 0 -SPIN_TYP: 0 -ELEC_TEMP_TYPE: Fermi-Dirac -ELEC_TEMP: 2400 -EXCHANGE_CORRELATION: GGA_PBE -NSTATES: 72 -CHEB_DEGREE: 26 -CHEFSI_BOUND_FLAG: 0 -CALC_STRESS: 1 -TWTIME: 1E+09 -MD_FLAG: 1 -MD_METHOD: NPT_NP -MD_TIMESTEP: 1 -MD_NSTEP: 10 -ION_VEL_DSTR: 2 -ION_VEL_DSTR_RAND: 0 -ION_TEMP: 2400 -NPT_SCALE_VECS: 3 -NPT_SCALE_CONSTRAINTS: none -NPT_NP_QMASS: 20000 -NPT_NP_BMASS: 1000 -TARGET_PRESSURE: 0.1 GPa -RESTART_FLAG: 1 -MAXIT_SCF: 100 -MINIT_SCF: 2 -MAXIT_POISSON: 3000 -TOL_SCF: 1.00E-06 -POISSON_SOLVER: AAR -TOL_POISSON: 1.00E-08 -TOL_LANCZOS: 1.00E-02 -TOL_PSEUDOCHARGE: 1.00E-09 -MIXING_VARIABLE: density -MIXING_PRECOND: kerker -TOL_PRECOND: 8.77E-05 -PRECOND_KERKER_KTF: 1 -PRECOND_KERKER_THRESH: 0 -MIXING_PARAMETER: 1 -MIXING_HISTORY: 7 -PULAY_FREQUENCY: 1 -PULAY_RESTART: 0 -REFERENCE_CUTOFF: 0.5 -RHO_TRIGGER: 4 -NUM_CHEFSI: 1 -FIX_RAND: 0 -VERBOSITY: 1 -PRINT_FORCES: 1 -PRINT_ATOMS: 1 -PRINT_EIGEN: 0 -PRINT_DENSITY: 0 -PRINT_MDOUT: 1 -PRINT_VELS: 1 -PRINT_RESTART: 1 -PRINT_RESTART_FQ: 1 -PRINT_ENERGY_DENSITY: 0 -OUTPUT_FILE: Al18C2_NPTNP_onlyc/temp_run/Al18C2_NPTNP_onlyc -*************************************************************************** - Cell -*************************************************************************** -Lattice vectors (Bohr): -13.322568219000001 0.000000000000000 0.000000000000000 -0.000000000000000 17.479965394000001 0.000000000000000 -0.000000000000000 0.000000000000000 13.020212061000001 -Volume: 3.0321213535E+03 (Bohr^3) -Density: 1.6809673281E-01 (amu/Bohr^3), 1.8836706501E+00 (g/cc) -*************************************************************************** - Parallelization -*************************************************************************** -NP_SPIN_PARAL: 1 -NP_KPOINT_PARAL: 1 -NP_BAND_PARAL: 24 -NP_DOMAIN_PARAL: 1 2 1 -NP_DOMAIN_PHI_PARAL: 4 4 3 -EIG_SERIAL_MAXNS: 1500 -*************************************************************************** - Initialization -*************************************************************************** -Number of processors : 48 -Mesh spacing in x-direction : 0.296057 (Bohr) -Mesh spacing in y-direction : 0.296271 (Bohr) -Mesh spacing in z-direction : 0.295914 (Bohr) -Number of symmetry adapted k-points: 1 -Output printed to : Al18C2_NPTNP_onlyc/temp_run/Al18C2_NPTNP_onlyc.out -MD output printed to : Al18C2_NPTNP_onlyc/temp_run/Al18C2_NPTNP_onlyc.aimd -Total number of atom types : 2 -Total number of atoms : 20 -Total number of electrons : 62 -Atom type 1 (valence electrons) : Al 3 -Pseudopotential : ../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 -Atomic mass : 26.9815385 -Pseudocharge radii of atom type 1 : 7.40 7.41 7.40 (x, y, z dir) -Number of atoms of type 1 : 18 -Atom type 2 (valence electrons) : C 4 -Pseudopotential : ../psps/06_C_4_1.2_1.2_pbe_n_v1.0.psp8 -Atomic mass : 12.011 -Pseudocharge radii of atom type 2 : 7.70 7.70 7.69 (x, y, z dir) -Number of atoms of type 2 : 2 -Estimated total memory usage : 486.54 MB -Estimated memory per processor : 10.14 MB -=================================================================== - Self Consistent Field (SCF#1) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6416593298E+00 1.490E-01 0.696 -2 -2.6418331372E+00 1.097E-01 0.208 -3 -2.6432599868E+00 1.873E-01 0.208 -4 -2.6411701109E+00 1.464E-02 0.201 -5 -2.6411623551E+00 8.770E-03 0.199 -6 -2.6411781051E+00 1.843E-02 0.202 -7 -2.6411630925E+00 2.036E-03 0.196 -8 -2.6411636184E+00 9.300E-04 0.195 -9 -2.6411638967E+00 3.375E-04 0.192 -10 -2.6411639244E+00 1.057E-04 0.192 -11 -2.6411639239E+00 2.406E-05 0.186 -12 -2.6411639268E+00 8.151E-06 0.184 -13 -2.6411639221E+00 5.822E-06 0.182 -14 -2.6411639239E+00 2.177E-06 0.179 -15 -2.6411639242E+00 1.298E-06 0.174 -16 -2.6411639238E+00 1.166E-06 0.173 -17 -2.6411639230E+00 1.890E-07 0.173 -Total number of SCF: 17 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6411639230E+00 (Ha/atom) -Total free energy : -5.2823278459E+01 (Ha) -Band structure energy : -4.6254100070E+00 (Ha) -Exchange correlation energy : -2.3093917821E+01 (Ha) -Self and correction energy : -7.6944144920E+01 (Ha) --Entropy*kb*T : -8.9556471848E-02 (Ha) -Fermi level : 8.3250269324E-02 (Ha) -RMS force : 5.7129795564E-02 (Ha/Bohr) -Maximum force : 8.4296371652E-02 (Ha/Bohr) -Time for force calculation : 0.044 (sec) -Pressure : 1.0501509997E+01 (GPa) -Maximum stress : 2.2117981642E+01 (GPa) -Time for stress calculation : 0.077 (sec) -MD step time : 4.001 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202134341207 -CHEB_DEGREE: 26 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.296057 (Bohr) -Mesh spacing in y-direction : 0.296271 (Bohr) -Mesh spacing in z direction : 0.295914 (Bohr) -=================================================================== - Self Consistent Field (SCF#2) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6415612454E+00 3.496E-02 0.217 -2 -2.6414285370E+00 5.374E-02 0.206 -3 -2.6413354151E+00 3.724E-02 0.202 -4 -2.6412658881E+00 1.148E-02 0.203 -5 -2.6412628265E+00 8.843E-03 0.200 -6 -2.6412586180E+00 1.050E-03 0.197 -7 -2.6412587473E+00 4.022E-04 0.196 -8 -2.6412588298E+00 1.705E-04 0.192 -9 -2.6412588480E+00 4.622E-05 0.191 -10 -2.6412588486E+00 1.494E-05 0.185 -11 -2.6412588498E+00 6.064E-06 0.183 -12 -2.6412588495E+00 6.228E-06 0.178 -13 -2.6412588540E+00 2.030E-06 0.177 -14 -2.6412588554E+00 2.195E-06 0.175 -15 -2.6412588528E+00 2.855E-07 0.175 -Total number of SCF: 15 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6412588528E+00 (Ha/atom) -Total free energy : -5.2825177055E+01 (Ha) -Band structure energy : -4.6250723181E+00 (Ha) -Exchange correlation energy : -2.3092651087E+01 (Ha) -Self and correction energy : -7.6944165008E+01 (Ha) --Entropy*kb*T : -8.9604604644E-02 (Ha) -Fermi level : 8.3242170610E-02 (Ha) -RMS force : 5.7133807591E-02 (Ha/Bohr) -Maximum force : 8.5865646772E-02 (Ha/Bohr) -Time for force calculation : 0.044 (sec) -Pressure : 1.0469080476E+01 (GPa) -Maximum stress : 2.2108768015E+01 (GPa) -Time for stress calculation : 0.077 (sec) -MD step time : 3.086 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202161803995 -CHEB_DEGREE: 26 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.296057 (Bohr) -Mesh spacing in y-direction : 0.296271 (Bohr) -Mesh spacing in z direction : 0.295914 (Bohr) -=================================================================== - Self Consistent Field (SCF#3) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6417671320E+00 3.553E-02 0.214 -2 -2.6415292189E+00 3.961E-02 0.206 -3 -2.6415594912E+00 4.875E-02 0.204 -4 -2.6414403188E+00 4.640E-03 0.203 -5 -2.6414422242E+00 7.683E-03 0.199 -6 -2.6414389211E+00 1.176E-03 0.199 -7 -2.6414390600E+00 4.278E-04 0.199 -8 -2.6414391511E+00 1.679E-04 0.193 -9 -2.6414391706E+00 4.245E-05 0.193 -10 -2.6414391715E+00 1.417E-05 0.186 -11 -2.6414391729E+00 6.384E-06 0.183 -12 -2.6414391727E+00 6.358E-06 0.180 -13 -2.6414391758E+00 3.854E-06 0.177 -14 -2.6414391761E+00 2.254E-06 0.175 -15 -2.6414391730E+00 5.080E-07 0.177 -Total number of SCF: 15 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6414391730E+00 (Ha/atom) -Total free energy : -5.2828783459E+01 (Ha) -Band structure energy : -4.6224988491E+00 (Ha) -Exchange correlation energy : -2.3090753735E+01 (Ha) -Self and correction energy : -7.6944211500E+01 (Ha) --Entropy*kb*T : -8.9604591012E-02 (Ha) -Fermi level : 8.3266403101E-02 (Ha) -RMS force : 5.7143450873E-02 (Ha/Bohr) -Maximum force : 8.7004888541E-02 (Ha/Bohr) -Time for force calculation : 0.042 (sec) -Pressure : 1.0414095289E+01 (GPa) -Maximum stress : 2.2114533463E+01 (GPa) -Time for stress calculation : 0.078 (sec) -MD step time : 3.090 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202203038899 -CHEB_DEGREE: 26 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.296057 (Bohr) -Mesh spacing in y-direction : 0.296271 (Bohr) -Mesh spacing in z direction : 0.295914 (Bohr) -=================================================================== - Self Consistent Field (SCF#4) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6416705852E+00 2.870E-03 0.198 -2 -2.6417055025E+00 9.386E-04 0.192 -3 -2.6417060056E+00 2.865E-03 0.196 -4 -2.6417055732E+00 2.967E-04 0.189 -5 -2.6417055748E+00 3.203E-04 0.189 -6 -2.6417055729E+00 3.069E-05 0.187 -7 -2.6417055702E+00 1.180E-05 0.184 -8 -2.6417055725E+00 5.606E-06 0.185 -9 -2.6417055707E+00 2.166E-06 0.181 -10 -2.6417055722E+00 6.304E-07 0.177 -Total number of SCF: 10 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6417055722E+00 (Ha/atom) -Total free energy : -5.2834111444E+01 (Ha) -Band structure energy : -4.6177954875E+00 (Ha) -Exchange correlation energy : -2.3088288764E+01 (Ha) -Self and correction energy : -7.6944281800E+01 (Ha) --Entropy*kb*T : -8.9546790194E-02 (Ha) -Fermi level : 8.3321081199E-02 (Ha) -RMS force : 5.7157729919E-02 (Ha/Bohr) -Maximum force : 8.7601139033E-02 (Ha/Bohr) -Time for force calculation : 0.043 (sec) -Pressure : 1.0336705250E+01 (GPa) -Maximum stress : 2.2133610691E+01 (GPa) -Time for stress calculation : 0.077 (sec) -MD step time : 2.072 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202258172506 -CHEB_DEGREE: 26 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.296057 (Bohr) -Mesh spacing in y-direction : 0.296271 (Bohr) -Mesh spacing in z direction : 0.295914 (Bohr) -=================================================================== - Self Consistent Field (SCF#5) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6420306026E+00 2.818E-03 0.198 -2 -2.6420643648E+00 7.521E-04 0.193 -3 -2.6420647274E+00 2.209E-03 0.194 -4 -2.6420644542E+00 2.470E-04 0.191 -5 -2.6420644590E+00 3.412E-04 0.189 -6 -2.6420644562E+00 3.445E-05 0.187 -7 -2.6420644526E+00 1.115E-05 0.192 -8 -2.6420644535E+00 4.996E-06 0.186 -9 -2.6420644532E+00 2.102E-06 0.180 -10 -2.6420644556E+00 5.699E-07 0.177 -Total number of SCF: 10 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6420644556E+00 (Ha/atom) -Total free energy : -5.2841289113E+01 (Ha) -Band structure energy : -4.6112518823E+00 (Ha) -Exchange correlation energy : -2.3085340094E+01 (Ha) -Self and correction energy : -7.6944369369E+01 (Ha) --Entropy*kb*T : -8.9415583087E-02 (Ha) -Fermi level : 8.3399930889E-02 (Ha) -RMS force : 5.7174102555E-02 (Ha/Bohr) -Maximum force : 8.7638806239E-02 (Ha/Bohr) -Time for force calculation : 0.042 (sec) -Pressure : 1.0235872685E+01 (GPa) -Maximum stress : 2.2160050022E+01 (GPa) -Time for stress calculation : 0.076 (sec) -MD step time : 2.078 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202327479634 -CHEB_DEGREE: 26 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.296057 (Bohr) -Mesh spacing in y-direction : 0.296271 (Bohr) -Mesh spacing in z direction : 0.295914 (Bohr) -=================================================================== - Self Consistent Field (SCF#6) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6424882717E+00 2.838E-03 0.198 -2 -2.6425231758E+00 5.941E-04 0.195 -3 -2.6425234375E+00 1.783E-03 0.193 -4 -2.6425232812E+00 2.078E-04 0.189 -5 -2.6425232806E+00 8.524E-05 0.189 -6 -2.6425232799E+00 1.350E-04 0.186 -7 -2.6425232802E+00 1.776E-05 0.188 -8 -2.6425232801E+00 5.729E-06 0.184 -9 -2.6425232788E+00 1.682E-06 0.179 -10 -2.6425232826E+00 6.651E-07 0.177 -Total number of SCF: 10 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6425232826E+00 (Ha/atom) -Total free energy : -5.2850465652E+01 (Ha) -Band structure energy : -4.6032180993E+00 (Ha) -Exchange correlation energy : -2.3082029569E+01 (Ha) -Self and correction energy : -7.6944459710E+01 (Ha) --Entropy*kb*T : -8.9194886930E-02 (Ha) -Fermi level : 8.3497858679E-02 (Ha) -RMS force : 5.7189445508E-02 (Ha/Bohr) -Maximum force : 8.7126154189E-02 (Ha/Bohr) -Time for force calculation : 0.044 (sec) -Pressure : 1.0111117324E+01 (GPa) -Maximum stress : 2.2185634781E+01 (GPa) -Time for stress calculation : 0.076 (sec) -MD step time : 2.075 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202411459538 -CHEB_DEGREE: 26 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.296057 (Bohr) -Mesh spacing in y-direction : 0.296271 (Bohr) -Mesh spacing in z direction : 0.295915 (Bohr) -=================================================================== - Self Consistent Field (SCF#7) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6430436947E+00 2.890E-03 0.201 -2 -2.6430796895E+00 1.393E-03 0.193 -3 -2.6430803671E+00 3.487E-03 0.193 -4 -2.6430797302E+00 3.801E-04 0.189 -5 -2.6430797293E+00 3.107E-04 0.191 -6 -2.6430797198E+00 5.281E-05 0.187 -7 -2.6430797200E+00 1.428E-05 0.186 -8 -2.6430797204E+00 6.694E-06 0.184 -9 -2.6430797206E+00 2.542E-06 0.181 -10 -2.6430797218E+00 6.207E-07 0.176 -Total number of SCF: 10 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6430797218E+00 (Ha/atom) -Total free energy : -5.2861594437E+01 (Ha) -Band structure energy : -4.5939845002E+00 (Ha) -Exchange correlation energy : -2.3078478919E+01 (Ha) -Self and correction energy : -7.6944534698E+01 (Ha) --Entropy*kb*T : -8.8871123542E-02 (Ha) -Fermi level : 8.3612141436E-02 (Ha) -RMS force : 5.7196393412E-02 (Ha/Bohr) -Maximum force : 8.6090119136E-02 (Ha/Bohr) -Time for force calculation : 0.042 (sec) -Pressure : 9.9629699891E+00 (GPa) -Maximum stress : 2.2201341571E+01 (GPa) -Time for stress calculation : 0.076 (sec) -MD step time : 2.072 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202510922568 -CHEB_DEGREE: 26 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.296057 (Bohr) -Mesh spacing in y-direction : 0.296271 (Bohr) -Mesh spacing in z direction : 0.295915 (Bohr) -=================================================================== - Self Consistent Field (SCF#8) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6436914056E+00 2.850E-03 0.198 -2 -2.6437281899E+00 9.570E-04 0.193 -3 -2.6437286822E+00 2.768E-03 0.194 -4 -2.6437282832E+00 2.128E-04 0.189 -5 -2.6437282854E+00 2.574E-04 0.190 -6 -2.6437282858E+00 5.766E-05 0.190 -7 -2.6437282834E+00 1.498E-05 0.189 -8 -2.6437282824E+00 6.018E-06 0.184 -9 -2.6437282836E+00 1.357E-06 0.180 -10 -2.6437282832E+00 6.258E-07 0.174 -Total number of SCF: 10 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6437282832E+00 (Ha/atom) -Total free energy : -5.2874565663E+01 (Ha) -Band structure energy : -4.5838920606E+00 (Ha) -Exchange correlation energy : -2.3074814654E+01 (Ha) -Self and correction energy : -7.6944579776E+01 (Ha) --Entropy*kb*T : -8.8433703576E-02 (Ha) -Fermi level : 8.3741340135E-02 (Ha) -RMS force : 5.7184492977E-02 (Ha/Bohr) -Maximum force : 8.4571587782E-02 (Ha/Bohr) -Time for force calculation : 0.043 (sec) -Pressure : 9.7927043942E+00 (GPa) -Maximum stress : 2.2195898205E+01 (GPa) -Time for stress calculation : 0.076 (sec) -MD step time : 2.074 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202627080844 -CHEB_DEGREE: 26 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.296057 (Bohr) -Mesh spacing in y-direction : 0.296271 (Bohr) -Mesh spacing in z direction : 0.295915 (Bohr) -=================================================================== - Self Consistent Field (SCF#9) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6444376960E+00 2.856E-03 0.198 -2 -2.6444738354E+00 6.952E-04 0.190 -3 -2.6444741022E+00 1.592E-03 0.193 -4 -2.6444739629E+00 2.603E-04 0.191 -5 -2.6444739578E+00 1.792E-04 0.204 -6 -2.6444739578E+00 1.315E-04 0.190 -7 -2.6444739566E+00 1.491E-05 0.188 -8 -2.6444739563E+00 6.189E-06 0.184 -9 -2.6444739566E+00 1.678E-06 0.178 -10 -2.6444739597E+00 5.098E-07 0.177 -Total number of SCF: 10 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6444739597E+00 (Ha/atom) -Total free energy : -5.2889479194E+01 (Ha) -Band structure energy : -4.5733440317E+00 (Ha) -Exchange correlation energy : -2.3071238325E+01 (Ha) -Self and correction energy : -7.6944597031E+01 (Ha) --Entropy*kb*T : -8.7879338736E-02 (Ha) -Fermi level : 8.3882419415E-02 (Ha) -RMS force : 5.7147378151E-02 (Ha/Bohr) -Maximum force : 8.7283815615E-02 (Ha/Bohr) -Time for force calculation : 0.042 (sec) -Pressure : 9.6010088116E+00 (GPa) -Maximum stress : 2.2154262961E+01 (GPa) -Time for stress calculation : 0.075 (sec) -MD step time : 2.082 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 13.322568219 17.479965394 13.0202761638145 -CHEB_DEGREE: 26 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.296057 (Bohr) -Mesh spacing in y-direction : 0.296271 (Bohr) -Mesh spacing in z direction : 0.295915 (Bohr) -=================================================================== - Self Consistent Field (SCF#10) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -2.6452910309E+00 2.901E-03 0.200 -2 -2.6453278395E+00 1.826E-03 0.195 -3 -2.6453285382E+00 3.658E-03 0.195 -4 -2.6453278184E+00 3.040E-04 0.192 -5 -2.6453278212E+00 3.691E-04 0.190 -6 -2.6453278169E+00 4.303E-05 0.189 -7 -2.6453278155E+00 1.498E-05 0.187 -8 -2.6453278147E+00 6.042E-06 0.182 -9 -2.6453278167E+00 1.672E-06 0.179 -10 -2.6453278157E+00 6.665E-07 0.176 -Total number of SCF: 10 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -2.6453278157E+00 (Ha/atom) -Total free energy : -5.2906556313E+01 (Ha) -Band structure energy : -4.5629010816E+00 (Ha) -Exchange correlation energy : -2.3067993852E+01 (Ha) -Self and correction energy : -7.6944612855E+01 (Ha) --Entropy*kb*T : -8.7207491118E-02 (Ha) -Fermi level : 8.4030402419E-02 (Ha) -RMS force : 5.7081439142E-02 (Ha/Bohr) -Maximum force : 9.0964378291E-02 (Ha/Bohr) -Time for force calculation : 0.043 (sec) -Pressure : 9.3892500761E+00 (GPa) -Maximum stress : 2.2061370896E+01 (GPa) -Time for stress calculation : 0.075 (sec) -MD step time : 2.076 (sec) -*************************************************************************** - Timing info -*************************************************************************** -Total walltime : 24.760 sec -___________________________________________________________________________ - -*************************************************************************** -* Material Physics & Mechanics Group, Georgia Tech * -* PI: Phanish Suryanarayana * -* List of contributors: See the documentation * -* Citation: See README.md or the documentation for details * -* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * -* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * -*************************************************************************** - diff --git a/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.inpt b/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.inpt deleted file mode 100644 index 2707f234..00000000 --- a/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.inpt +++ /dev/null @@ -1,38 +0,0 @@ -# nprocs: 24 - -# Test: Si18Al18 -LATVEC: -0.5 0.5 0.0 -0.0 0.5 0.5 -0.5 0.0 0.5 -LATVEC_SCALE: 30.96 30.96 20.64 # 3 3 2 Si8(2) cell -MESH_SPACING: 0.30 -FD_ORDER: 12 -BC: P P P -KPOINT_GRID: 1 1 1 -EXCHANGE_CORRELATION: GGA_PBE -ELEC_TEMP_TYPE: fermi-dirac -ELEC_TEMP: 1000 -TOL_SCF: 5e-7 -CALC_STRESS: 1 -PRINT_FORCES: 1 -PRINT_ATOMS: 1 -MIXING_VARIABLE: potential -MIXING_PRECOND: kerker -# NSTATES: 135 - -# MD -MD_FLAG: 1 # 1 = MD, 0 = no MD (default) -ION_TEMP: 1000 # kelvin -# ION_TEMP_END: 1120 -MD_METHOD: NPT_NP # NVE, NVT_NH (Nose-Hoover), NVK_G (Gaussian) -#QMASS: 1600 # mass for NH thermostat -MD_TIMESTEP: 0.4 # fs 0.6 -MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whichever comes first -#TWTIME: 1400 -RESTART_FLAG: 0 # 1 = restart MD from .restart file if present, 0 = start new -# ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) -TARGET_PRESSURE: 12 GPa -NPT_NP_QMASS: 500.0 -NPT_NP_BMASS: 0.05 -NPT_SCALE_CONSTRAINTS: 123 diff --git a/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.ion b/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.ion deleted file mode 100644 index dc7c22bc..00000000 --- a/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.ion +++ /dev/null @@ -1,63 +0,0 @@ -#========================= -# format of ion file -#========================= -# ATOM_TYPE: -# N_TYPE_ATOM: -# COORD: -# -# ... -# RELAX: -# -# ... - - -# Reminder: when changing number of atoms, change the RELAX flags accordingly -# as well. - -ATOM_TYPE: Si # atom type followed with valence charge -N_TYPE_ATOM: 18 # number of atoms of this type -PSEUDO_POT: ../../../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 -ATOMIC_MASS: 28.0855 -COORD_FRAC: # coordinates follows -0.003 0.004 0.006 -0.3363 0.004 0.006 -0.6697 0.004 0.006 -0.003 0.337 0.006 -0.3363 0.337 0.006 -0.6697 0.337 0.006 -0.003 0.671 0.006 -0.3363 0.671 0.006 -0.6697 0.671 0.006 -0.003 0.004 0.501 -0.3363 0.004 0.501 -0.6697 0.004 0.501 -0.003 0.337 0.501 -0.3363 0.337 0.501 -0.6697 0.337 0.501 -0.003 0.671 0.501 -0.3363 0.671 0.501 -0.6697 0.671 0.501 - -ATOM_TYPE: Al # atom type followed with valence charge -N_TYPE_ATOM: 18 # number of atoms of this type -PSEUDO_POT: ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 -ATOMIC_MASS: 26.9815385 -COORD_FRAC: # coordinates follows -0.083333333 0.083333333 0.125 -0.416633333 0.083333333 0.125 -0.750033333 0.083333333 0.125 -0.083333333 0.416333333 0.125 -0.416633333 0.416333333 0.125 -0.750033333 0.416333333 0.125 -0.083333333 0.750333333 0.125 -0.416633333 0.750333333 0.125 -0.750033333 0.750333333 0.125 -0.083333333 0.083333333 0.62 -0.416633333 0.083333333 0.62 -0.750033333 0.083333333 0.62 -0.083333333 0.416333333 0.62 -0.416633333 0.416333333 0.62 -0.750033333 0.416333333 0.62 -0.083333333 0.750333333 0.62 -0.416633333 0.750333333 0.62 -0.750033333 0.750333333 0.62 diff --git a/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.refaimd b/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.refaimd deleted file mode 100644 index b2bb5386..00000000 --- a/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.refaimd +++ /dev/null @@ -1,1419 +0,0 @@ -:Description: - -:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr -:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu - where atu is the atomic unit of time, hbar/Ha -:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr -:Desc_MDTM: MD time. Unit=second -:Desc_TEL: Electronic temperature. Unit=Kelvin -:Desc_TIO: Ionic temperature. Unit=Kelvin -:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom -:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom -:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom - where N = number of particles, k = Boltzmann constant -:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom -:Desc_UEN: Internal energy. Unit=Ha/atom -:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom -:Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 -:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom -:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa -:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa -:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa - where N = number of particles, k = Boltzmann constant, V = volume -:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr - - -:MDSTEP: 1 -:MDTM: 19.46 -:TWIST: 0 -:TEL: 1000 -:TIO: 1000 -:TEN: -3.2422551573E+00 -:KEN: 4.6182668634E-03 -:KENIG: 4.7502173452E-03 -:FEN: -3.2468734241E+00 -:UEN: -3.2459708634E+00 -:TSEN: -9.0256070747E-04 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 1.0836000000E-01 1.0836000000E-01 1.2384000000E-01 - 5.2678440000E+00 5.2678440000E+00 1.2384000000E-01 - 1.0428876000E+01 1.0428876000E+01 1.2384000000E-01 - 1.0836000000E-01 5.2632000000E+00 5.2786800000E+00 - 5.2678440000E+00 1.0422684000E+01 5.2786800000E+00 - 1.0428876000E+01 1.5583716000E+01 5.2786800000E+00 - 1.0836000000E-01 1.0433520000E+01 1.0449000000E+01 - 5.2678440000E+00 1.5593004000E+01 1.0449000000E+01 - 1.0428876000E+01 2.0754036000E+01 1.0449000000E+01 - 5.2167600000E+00 1.0836000000E-01 5.2322400000E+00 - 1.0376244000E+01 5.2678440000E+00 5.2322400000E+00 - 1.5537276000E+01 1.0428876000E+01 5.2322400000E+00 - 5.2167600000E+00 5.2632000000E+00 1.0387080000E+01 - 1.0376244000E+01 1.0422684000E+01 1.0387080000E+01 - 1.5537276000E+01 1.5583716000E+01 1.0387080000E+01 - 5.2167600000E+00 1.0433520000E+01 1.5557400000E+01 - 1.0376244000E+01 1.5593004000E+01 1.5557400000E+01 - 1.5537276000E+01 2.0754036000E+01 1.5557400000E+01 - 2.5799999948E+00 2.5799999897E+00 2.5799999948E+00 - 7.7394839948E+00 7.7394839897E+00 2.5799999948E+00 - 1.2900515995E+01 1.2900515990E+01 2.5799999948E+00 - 2.5799999948E+00 7.7348399897E+00 7.7348399948E+00 - 7.7394839948E+00 1.2894323990E+01 7.7348399948E+00 - 1.2900515995E+01 1.8055355990E+01 7.7348399948E+00 - 2.5799999948E+00 1.2905159990E+01 1.2905159995E+01 - 7.7394839948E+00 1.8064643990E+01 1.2905159995E+01 - 1.2900515995E+01 2.3225675990E+01 1.2905159995E+01 - 7.6883999948E+00 2.5799999897E+00 7.6883999948E+00 - 1.2847883995E+01 7.7394839897E+00 7.6883999948E+00 - 1.8008915995E+01 1.2900515990E+01 7.6883999948E+00 - 7.6883999948E+00 7.7348399897E+00 1.2843239995E+01 - 1.2847883995E+01 1.2894323990E+01 1.2843239995E+01 - 1.8008915995E+01 1.8055355990E+01 1.2843239995E+01 - 7.6883999948E+00 1.2905159990E+01 1.8013559995E+01 - 1.2847883995E+01 1.8064643990E+01 1.8013559995E+01 - 1.8008915995E+01 2.3225675990E+01 1.8013559995E+01 -:V: - -6.0245009366E-07 5.0610838342E-04 3.0608266695E-04 - 2.9938984517E-05 -7.8901597789E-05 3.6016903910E-04 - 4.4972762428E-04 -2.8444441337E-04 -2.1122595649E-04 - -2.2481092799E-04 -6.4308057382E-05 -3.0900434353E-04 - 2.0159013658E-04 3.1059192089E-04 -2.1544169161E-05 - -1.1635182314E-04 2.8600741191E-04 -3.9508449999E-05 - -5.4680597612E-04 -3.8068816092E-04 1.8606202609E-04 - 3.2800903095E-05 1.2068768104E-04 2.7417358068E-04 - 3.1797054100E-04 -2.9842962794E-04 1.0359838584E-04 - -3.0676290696E-04 1.1167632141E-05 -4.2615937266E-04 - 1.6878744722E-05 4.3374116342E-05 -2.1120686257E-04 - 7.0760181861E-05 -2.9900063254E-04 3.0300451979E-04 - 3.8368497007E-04 -2.4059320899E-06 2.6540479441E-04 - 5.4747359958E-04 2.7168591071E-04 -3.3368346166E-05 - -4.7929758031E-04 4.2557459113E-04 -2.0470058895E-04 - 4.5340025918E-05 -5.5027479884E-04 -3.9120591677E-05 - -2.1924503718E-04 4.4304085342E-04 -1.7492054567E-05 - -9.5118584190E-05 3.6704244143E-05 -2.9582607050E-04 - 1.2197128562E-04 1.1395578019E-04 1.4006655013E-04 - -1.4267212210E-04 8.0783386218E-06 -5.7486714718E-05 - 1.9411669186E-04 -3.0664672216E-04 -5.0071124004E-04 - -1.3008652719E-04 -9.5604641977E-05 -2.0021704404E-04 - -5.9220663824E-05 -1.4618834423E-04 1.6024106415E-04 - -2.6504261105E-04 5.0003042978E-05 -1.0868544585E-04 - 1.6420255400E-04 2.2604163647E-04 1.4620774400E-04 - -5.1205374341E-04 -6.5216683506E-05 1.7672092139E-05 - 1.9123267548E-04 -2.2013241880E-04 -3.3512644184E-04 - 1.8242179630E-05 -2.2469638365E-04 3.1701805888E-04 - 2.7575448470E-04 -1.3396672528E-04 6.7237077754E-05 - -1.9035475988E-04 1.5510168323E-04 1.9749233591E-04 - -7.0764929449E-05 -2.2635554084E-05 9.6448428348E-05 - -8.9992731496E-05 -3.9118784261E-04 -5.1654558178E-04 - 1.3741131460E-04 2.9394207988E-04 3.6994077957E-04 - 2.2240738324E-04 -7.3145707163E-06 1.0717984225E-04 - 1.5069227647E-04 2.4275500768E-04 4.4585407812E-05 - -1.2739810789E-04 6.9087067276E-06 6.5781112690E-05 -:F: - -1.1952002850E-02 -8.2688740595E-03 -1.2342690969E-02 - -1.1927253270E-02 -8.2570019131E-03 -1.2361453895E-02 - -1.2076194023E-02 -8.3945386340E-03 -1.2283136589E-02 - -1.2087123626E-02 -8.2094224794E-03 -1.2302192279E-02 - -1.2085760128E-02 -8.2289348645E-03 -1.2338848426E-02 - -1.2193730245E-02 -8.3002113393E-03 -1.2224964727E-02 - -1.1236548481E-02 -9.1342911391E-03 -1.3294992280E-02 - -1.1190673764E-02 -9.0809986433E-03 -1.3288317878E-02 - -1.1313489166E-02 -9.1954994684E-03 -1.3185771322E-02 - -5.2361265723E-03 -1.3372477469E-02 -5.5778559821E-03 - -5.2485931254E-03 -1.3382993885E-02 -5.6230110654E-03 - -5.3525319933E-03 -1.3485490829E-02 -5.5142638335E-03 - -5.4009889946E-03 -1.3337400582E-02 -5.5668278032E-03 - -5.3808621945E-03 -1.3317750348E-02 -5.5760147586E-03 - -5.4842864345E-03 -1.3403929687E-02 -5.4563460920E-03 - -4.5148351652E-03 -1.4216684703E-02 -6.5172549158E-03 - -4.4844639939E-03 -1.4180780989E-02 -6.5302476549E-03 - -4.6285018152E-03 -1.4321034009E-02 -6.4506424214E-03 - 5.6896783089E-03 1.3191806961E-02 6.0330212181E-03 - 5.8055620668E-03 1.3309824786E-02 5.9460755949E-03 - 5.7438770331E-03 1.3247844571E-02 6.0466560191E-03 - 4.9686461086E-03 1.4021831150E-02 6.9276324777E-03 - 5.1005031006E-03 1.4148532609E-02 6.8566469225E-03 - 4.9883202793E-03 1.4034163271E-02 6.9185808959E-03 - 5.7547818357E-03 1.3243034510E-02 6.0937276171E-03 - 5.8409249757E-03 1.3311261575E-02 5.9687252026E-03 - 5.7562998353E-03 1.3236809943E-02 6.0560867656E-03 - 1.1521395868E-02 8.3682180112E-03 1.1893703984E-02 - 1.1660258869E-02 8.5078526539E-03 1.1828197745E-02 - 1.1554238949E-02 8.4049634195E-03 1.1893754675E-02 - 1.0829534460E-02 9.2210353823E-03 1.2808294499E-02 - 1.0917498106E-02 9.3098275138E-03 1.2692969480E-02 - 1.0820600711E-02 9.2131297432E-03 1.2764496181E-02 - 1.1567576312E-02 8.3922600758E-03 1.1933423651E-02 - 1.1665445149E-02 8.4924088539E-03 1.1832436327E-02 - 1.1608823876E-02 8.4335100103E-03 1.1940403637E-02 -:LATVEC_SCALE: 3.0960000000E+01 3.0960000000E+01 2.0640000000E+01 -:STRIO: - -6.8163081252E-01 4.4511004792E-02 -9.4040732941E-02 - 4.4511004792E-02 -6.7955659619E-01 -1.3243527596E-01 - -9.4040732941E-02 -1.3243527596E-01 -6.1677292168E-01 -:STRESS: - -1.5695363190E+01 -5.1698104078E+00 -3.8880853188E+00 - -5.1698104078E+00 -8.7221650543E+00 -4.6761079626E+00 - -3.8880853188E+00 -4.6761079626E+00 -1.5374291311E+01 -:PRESIO: 6.5932011013E-01 -:PRES: 1.3263939851E+01 -:PRESIG: 6.7815782756E-01 -:MIND: -Si - Si: 7.2243685620E+00 -Al - Al: 7.2243685620E+00 -Si - Al: 4.2720873613E+00 -:MDSTEP: 2 -:MDTM: 12.33 -:TWIST: 0 -:TEL: 1000 -:TIO: 998.91207588603 -:TEN: -3.2422552453E+00 -:KEN: 4.6132425395E-03 -:KENIG: 4.7450494692E-03 -:FEN: -3.2468684878E+00 -:UEN: -3.2459666952E+00 -:TSEN: -9.0179268691E-04 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 1.0828748328E-01 1.1668661677E-01 1.2883722191E-01 - 5.2683379533E+00 5.2665576646E+00 1.2973154623E-01 - 1.0436372482E+01 1.0424251169E+01 1.2028282445E-01 - 1.0457903337E-01 5.2621551965E+00 5.2735669847E+00 - 5.2711756960E+00 1.0427900076E+01 5.2783205083E+00 - 1.0427010617E+01 1.5588586435E+01 5.2780240418E+00 - 9.9258755225E-02 1.0427299693E+01 1.0452129982E+01 - 5.2683892151E+00 1.5595136488E+01 1.0453587115E+01 - 1.0434197693E+01 2.0749298241E+01 1.0450766867E+01 - 5.2117210588E+00 1.0847453736E-01 5.2252249619E+00 - 1.0376618319E+01 5.2685523539E+00 5.2287793833E+00 - 1.5538602092E+01 1.0423983260E+01 5.2372834608E+00 - 5.2231380919E+00 5.2631514791E+00 1.0391562615E+01 - 1.0385392042E+01 1.0427229507E+01 1.0386621764E+01 - 1.5529505102E+01 1.5590867192E+01 1.0383789088E+01 - 5.2175476261E+00 1.0424468097E+01 1.5556903015E+01 - 1.0372717629E+01 1.5600439992E+01 1.5557260616E+01 - 1.5535862828E+01 2.0754812961E+01 1.5552658241E+01 - 2.5820793051E+00 2.5819884596E+00 2.5823804549E+00 - 7.7372488253E+00 7.7397834991E+00 2.5791130397E+00 - 1.2903911241E+01 1.2895671850E+01 2.5717840096E+00 - 2.5779070245E+00 7.7334288007E+00 7.7316593903E+00 - 7.7386249391E+00 1.2892138279E+01 7.7376198795E+00 - 1.2896313938E+01 1.8056475347E+01 7.7331729950E+00 - 2.5827780442E+00 1.2909124928E+01 1.2907764973E+01 - 7.7311405702E+00 1.8063854053E+01 1.2905638688E+01 - 1.2903863617E+01 2.3222385097E+01 1.2899804956E+01 - 7.6888570330E+00 2.5763613608E+00 7.6937999499E+00 - 1.2852661553E+01 7.7374078057E+00 7.6896689659E+00 - 1.8006046224E+01 1.2903280842E+01 7.6918233572E+00 - 7.6873812787E+00 7.7346087957E+00 1.2845058702E+01 - 1.2846609073E+01 1.2888059827E+01 1.2834920999E+01 - 1.8011462401E+01 1.8060482554E+01 1.2849581193E+01 - 7.6922335630E+00 1.2905238954E+01 1.8015612707E+01 - 1.2850593432E+01 1.8068920178E+01 1.8014577023E+01 - 1.8007087639E+01 2.3226112962E+01 1.8014928136E+01 -:V: - -4.4631733389E-06 5.0346295945E-04 3.0211123228E-04 - 2.6087798098E-05 -8.1572729183E-05 3.5619427499E-04 - 4.4584952639E-04 -2.8717035105E-04 -2.1520427760E-04 - -2.2872661973E-04 -6.6963082882E-05 -3.1299375764E-04 - 1.9769641803E-04 3.0794952457E-04 -2.5530907400E-05 - -1.2029647350E-04 2.8334075063E-04 -4.3459309111E-05 - -5.5046317852E-04 -3.8365791097E-04 1.8177692158E-04 - 2.9187788453E-05 1.1776046422E-04 2.6989508164E-04 - 3.1433215570E-04 -3.0141499534E-04 9.9344397174E-05 - -3.0846975283E-04 6.8486666865E-06 -4.2798263211E-04 - 1.5184215471E-05 3.9053380303E-05 -2.1303385301E-04 - 6.9034799602E-05 -3.0337176629E-04 3.0123862356E-04 - 3.8195973774E-04 -6.7142525839E-06 2.6362002041E-04 - 5.4576313967E-04 2.6739777888E-04 -3.5171175390E-05 - -4.8109329868E-04 4.2126639316E-04 -2.0647341531E-04 - 4.3883949776E-05 -5.5489480925E-04 -4.1227747381E-05 - -2.2070466417E-04 4.3848260177E-04 -1.9602314922E-05 - -9.6618469517E-05 3.2080168948E-05 -2.9792467260E-04 - 1.2389050120E-04 1.1839705233E-04 1.4210212263E-04 - -1.4072730678E-04 1.2553945534E-05 -5.5490352391E-05 - 1.9605777409E-04 -3.0220784827E-04 -4.9870344160E-04 - -1.2842247487E-04 -9.0894871076E-05 -1.9789785786E-04 - -5.7508698223E-05 -1.4143852657E-04 1.6255458538E-04 - -2.6337875875E-04 5.4724313358E-05 -1.0636468086E-04 - 1.6614579215E-04 2.3050579319E-04 1.4826403811E-04 - -5.1011569127E-04 -6.0744294811E-05 1.9679865437E-05 - 1.9317778901E-04 -2.1569288624E-04 -3.3310711064E-04 - 2.2116971434E-05 -2.2189406161E-04 3.2103312070E-04 - 2.7968897086E-04 -1.3111287176E-04 7.1217500581E-05 - -1.8647945905E-04 1.5793553963E-04 2.0150137886E-04 - -6.7127258862E-05 -1.9536283085E-05 1.0075986694E-04 - -8.6326455632E-05 -3.8807732825E-04 -5.1230387471E-04 - 1.4105649403E-04 2.9705467954E-04 3.7425130278E-04 - 2.2630801252E-04 -4.4931874246E-06 1.1119766254E-04 - 1.5462219094E-04 2.4562269249E-04 4.8566111906E-05 - -1.2350127459E-04 9.7446778569E-06 6.9799189288E-05 -:F: - -1.2052498903E-02 -8.5918005788E-03 -1.2771861192E-02 - -1.2043812805E-02 -8.3912780618E-03 -1.2688947789E-02 - -1.2750427335E-02 -8.7171938569E-03 -1.2478549861E-02 - -1.1828886903E-02 -8.1103161576E-03 -1.1798862202E-02 - -1.2702080128E-02 -8.5881309589E-03 -1.2480837965E-02 - -1.2080961634E-02 -9.3218750719E-03 -1.2827624874E-02 - -9.4780116539E-03 -8.1159509262E-03 -1.2905281408E-02 - -1.1649556159E-02 -9.6249003694E-03 -1.4346405308E-02 - -1.2371680732E-02 -9.3678583165E-03 -1.3252396755E-02 - -4.3172231368E-03 -1.3015996205E-02 -4.5683994466E-03 - -5.4216442254E-03 -1.3284081925E-02 -5.0936692508E-03 - -5.4336947312E-03 -1.3020459771E-02 -5.7678222660E-03 - -6.3282252487E-03 -1.3408410249E-02 -6.4309449948E-03 - -6.9923356253E-03 -1.4700152031E-02 -6.4035843733E-03 - -4.4942688504E-03 -1.2774517951E-02 -4.5411345185E-03 - -4.1972338517E-03 -1.3317576699E-02 -5.9779852696E-03 - -3.8387277946E-03 -1.4319869781E-02 -6.7562799954E-03 - -4.4035565373E-03 -1.4075512831E-02 -5.7079866746E-03 - 5.6540854966E-03 1.3451108634E-02 5.9637200022E-03 - 6.1535372448E-03 1.3912278751E-02 6.1184567334E-03 - 5.8751784751E-03 1.3693051943E-02 7.0969904681E-03 - 5.4817094005E-03 1.4004563260E-02 7.1526474616E-03 - 5.3407194243E-03 1.4435235404E-02 7.2735224497E-03 - 5.2681318406E-03 1.4274545921E-02 6.7801435340E-03 - 4.8212202995E-03 1.2396642870E-02 5.6395268723E-03 - 6.6222910386E-03 1.4165057411E-02 6.2101592040E-03 - 5.2603583057E-03 1.3108671317E-02 6.5738844428E-03 - 1.1085481093E-02 8.0800879168E-03 1.0903549768E-02 - 1.1184246830E-02 8.0902306334E-03 1.1790915259E-02 - 1.1694515372E-02 8.3416764332E-03 1.2085348088E-02 - 1.1623349170E-02 9.9993577110E-03 1.2316410975E-02 - 1.1893165925E-02 1.0614910635E-02 1.4460041861E-02 - 1.0230743429E-02 8.3109553351E-03 1.1515504737E-02 - 1.0938170497E-02 7.9668988413E-03 1.1183713716E-02 - 1.1731622485E-02 8.0261797600E-03 1.1693754440E-02 - 1.1526299929E-02 7.8744289657E-03 1.2040284131E-02 -:LATVEC_SCALE: 3.0960367687E+01 3.0960367687E+01 2.0640245125E+01 -:STRIO: - -6.8170069346E-01 4.5497508536E-02 -9.4169270212E-02 - 4.5497508536E-02 -6.7736350742E-01 -1.3185106365E-01 - -9.4169270212E-02 -1.3185106365E-01 -6.1687341503E-01 -:STRESS: - -1.5696517346E+01 -5.1694001222E+00 -3.9227336943E+00 - -5.1694001222E+00 -8.7133124540E+00 -4.6843187899E+00 - -3.9227336943E+00 -4.6843187899E+00 -1.5380314836E+01 -:PRESIO: 6.5864587197E-01 -:PRES: 1.3263381546E+01 -:PRESIG: 6.7739590834E-01 -:MIND: -Si - Si: 7.2123692151E+00 -Al - Al: 7.2162315135E+00 -Si - Al: 4.2552842785E+00 -:MDSTEP: 3 -:MDTM: 10.11 -:TWIST: 0 -:TEL: 1000 -:TIO: 997.05189450416 -:TEN: -3.2422570647E+00 -:KEN: 4.6046517255E-03 -:KENIG: 4.7362132033E-03 -:FEN: -3.2468617164E+00 -:UEN: -3.2459605381E+00 -:TSEN: -9.0117835535E-04 -:NPT_NP_HAMIL: 2.0131335011E-06 -:R: - 1.0815184759E-01 1.2497053429E-01 1.3376883145E-01 - 5.2688301699E+00 5.2652886959E+00 1.3555812873E-01 - 1.0443926287E+01 1.0419702419E+01 1.1665963603E-01 - 1.0073528945E-01 5.2611292611E+00 5.2684523802E+00 - 5.2745027914E+00 1.0433195113E+01 5.2779568773E+00 - 1.0425203980E+01 1.5593593057E+01 5.2773620237E+00 - 9.0106068548E-02 1.0421158368E+01 1.0455315693E+01 - 5.2689348116E+00 1.5597403024E+01 1.0458222597E+01 - 1.0439578233E+01 2.0744755547E+01 1.0452587295E+01 - 5.2067197800E+00 1.0852085150E-01 5.2182459735E+00 - 1.0377086850E+01 5.2692523945E+00 5.2253528276E+00 - 1.5540083776E+01 1.0419143551E+01 5.2423593369E+00 - 5.2295457286E+00 5.2630937516E+00 1.0396135123E+01 - 1.0394627923E+01 1.0431821168E+01 1.0386252432E+01 - 1.5521892721E+01 1.5598136649E+01 1.0380596377E+01 - 5.2183748956E+00 1.0415466736E+01 1.5556558534E+01 - 1.0369293030E+01 1.5607986169E+01 1.5557269660E+01 - 1.5534610121E+01 2.0755761105E+01 1.5548069452E+01 - 2.5842211410E+00 2.5840827923E+00 2.5848252317E+00 - 7.7351391720E+00 7.7402522530E+00 2.5782905102E+00 - 1.2907492975E+01 1.2891055777E+01 2.5636362060E+00 - 2.5758746616E+00 7.7321869208E+00 7.7286095855E+00 - 7.7378871963E+00 1.2890185300E+01 7.7405326068E+00 - 1.2892293246E+01 1.8057888527E+01 7.7316350716E+00 - 2.5856141484E+00 1.2913312805E+01 1.2910555001E+01 - 7.7229238638E+00 1.8063357002E+01 1.2906305116E+01 - 1.2907394297E+01 2.3219441862E+01 1.2894638333E+01 - 7.6894670265E+00 2.5727974332E+00 7.6993529854E+00 - 1.2857654814E+01 7.7354679442E+00 7.6910950017E+00 - 1.8003454459E+01 1.2906245752E+01 7.6954059173E+00 - 7.6865181694E+00 7.7345249099E+00 1.2847098674E+01 - 1.2845552406E+01 1.2882006215E+01 1.2826832857E+01 - 1.8014279920E+01 1.8065870700E+01 1.2856140241E+01 - 7.6962200439E+00 1.2905515330E+01 1.8017941772E+01 - 1.2853521141E+01 1.8073456279E+01 1.8015873003E+01 - 1.8005536594E+01 2.3226869343E+01 1.8016577237E+01 -:V: - -8.3591563250E-06 5.0086905387E-04 2.9809378964E-04 - 2.2205681050E-05 -8.4313622766E-05 3.5222320089E-04 - 4.4189104200E-04 -2.9009097897E-04 -2.1931421222E-04 - -2.3263153222E-04 -6.9607904271E-05 -3.1691947295E-04 - 1.9366372515E-04 3.0528602975E-04 -2.9572920444E-05 - -1.2424358441E-04 2.8043126235E-04 -4.7619864902E-05 - -5.5372495040E-04 -3.8641919513E-04 1.7767280813E-04 - 2.5434184614E-05 1.1469312399E-04 2.6535721493E-04 - 3.1044844209E-04 -3.0455102050E-04 9.5098284655E-05 - -3.0997638568E-04 2.6454561732E-06 -4.2961368741E-04 - 1.3437886648E-05 3.4775204694E-05 -2.1475682144E-04 - 6.7304070721E-05 -3.0768871744E-04 2.9948398911E-04 - 3.8005324824E-04 -1.1049168462E-05 2.6163750198E-04 - 5.4370136089E-04 2.6274470657E-04 -3.7253014193E-05 - -4.8271962695E-04 4.1729122570E-04 -2.0801547553E-04 - 4.2543637937E-05 -5.5939881412E-04 -4.3174260328E-05 - -2.2202491647E-04 4.3401433704E-04 -2.1792479822E-05 - -9.8076308958E-05 2.7543744285E-05 -2.9987686752E-04 - 1.2583702985E-04 1.2296402348E-04 1.4415938550E-04 - -1.3870858422E-04 1.7237710758E-05 -5.3452573336E-05 - 1.9810478882E-04 -2.9771175957E-04 -4.9649698609E-04 - -1.2662525890E-04 -8.6217515113E-05 -1.9556379257E-04 - -5.5733232006E-05 -1.3663461600E-04 1.6505978759E-04 - -2.6170223048E-04 5.9545188088E-05 -1.0412276801E-04 - 1.6782749324E-04 2.3475869084E-04 1.5021449326E-04 - -5.0807302615E-04 -5.6002044279E-05 2.1775698745E-05 - 1.9501697414E-04 -2.1136202863E-04 -3.3101665017E-04 - 2.5853440433E-05 -2.1925674986E-04 3.2481660566E-04 - 2.8355189836E-04 -1.2843928625E-04 7.5209007696E-05 - -1.8261365996E-04 1.6079832999E-04 2.0563907694E-04 - -6.3242190674E-05 -1.6180196373E-05 1.0493881216E-04 - -8.2357587978E-05 -3.8464761819E-04 -5.0762587236E-04 - 1.4454853828E-04 2.9995749774E-04 3.7825987586E-04 - 2.3006885167E-04 -1.8152472720E-06 1.1499941765E-04 - 1.5862394779E-04 2.4841111184E-04 5.2516740497E-05 - -1.1966925483E-04 1.2396670967E-05 7.3874055078E-05 -:F: - -1.2145873319E-02 -8.9103325649E-03 -1.3176922335E-02 - -1.2141591160E-02 -8.5159326649E-03 -1.3004174140E-02 - -1.3410567014E-02 -9.0362118702E-03 -1.2660104573E-02 - -1.1554820678E-02 -8.0079465688E-03 -1.1279054331E-02 - -1.3303050293E-02 -8.9382619951E-03 -1.2616539431E-02 - -1.1963890012E-02 -1.0323494525E-02 -1.3401427268E-02 - -7.7117898602E-03 -7.0891805580E-03 -1.2547129492E-02 - -1.2104198072E-02 -1.0169461073E-02 -1.5398941709E-02 - -1.3414629103E-02 -9.5296599682E-03 -1.3295690156E-02 - -3.3889164301E-03 -1.2670416260E-02 -3.5474569059E-03 - -5.5839481337E-03 -1.3170251769E-02 -4.5622067582E-03 - -5.5001998550E-03 -1.2543492980E-02 -6.0150171545E-03 - -7.2450275097E-03 -1.3480946546E-02 -7.2846636369E-03 - -8.6357914155E-03 -1.6104202740E-02 -7.2784458345E-03 - -3.5091852426E-03 -1.2158273084E-02 -3.6244804668E-03 - -3.8914468277E-03 -1.2410182332E-02 -5.4370434876E-03 - -3.2045087513E-03 -1.4432045455E-02 -6.9574980184E-03 - -4.1769060840E-03 -1.3816081419E-02 -4.9518997210E-03 - 5.6023150941E-03 1.3705840762E-02 5.8858319724E-03 - 6.4942242677E-03 1.4503169119E-02 6.2845563360E-03 - 6.0143048998E-03 1.4124901522E-02 8.1228316806E-03 - 5.9772221277E-03 1.3980188060E-02 7.3669689056E-03 - 5.5763903136E-03 1.4707015698E-02 7.6853649245E-03 - 5.5415653156E-03 1.4501593463E-02 6.6234431527E-03 - 3.9009764146E-03 1.1550469331E-02 5.2042488778E-03 - 7.4028551455E-03 1.5014178141E-02 6.4585257451E-03 - 4.7415165309E-03 1.2952168179E-02 7.0967095410E-03 - 1.0633560177E-02 7.7934651503E-03 9.9014932537E-03 - 1.0691784675E-02 7.6656216088E-03 1.1746275015E-02 - 1.1820046101E-02 8.2714020927E-03 1.2256450933E-02 - 1.2403383992E-02 1.0764967852E-02 1.1817354131E-02 - 1.2921296927E-02 1.1937552286E-02 1.6240315492E-02 - 9.6428014527E-03 7.4213556580E-03 1.0258192162E-02 - 1.0309790372E-02 7.5455123039E-03 1.0433778528E-02 - 1.1784658053E-02 7.5548036162E-03 1.1538018686E-02 - 1.1427647903E-02 7.3121695319E-03 1.2118336082E-02 -:LATVEC_SCALE: 3.0961102730E+01 3.0961102730E+01 2.0640735153E+01 -:STRIO: - -6.8131725106E-01 4.6697571077E-02 -9.4140580682E-02 - 4.6697571077E-02 -6.7532043667E-01 -1.3118283415E-01 - -9.4140580682E-02 -1.3118283415E-01 -6.1670860205E-01 -:STRESS: - -1.5693526044E+01 -5.1646928799E+00 -3.9517547433E+00 - -5.1646928799E+00 -8.7044606785E+00 -4.6890373590E+00 - -3.9517547433E+00 -4.6890373590E+00 -1.5383314063E+01 -:PRESIO: 6.5778209660E-01 -:PRES: 1.3260433595E+01 -:PRESIG: 6.7608630189E-01 -:MIND: -Si - Si: 7.2005259087E+00 -Al - Al: 7.2082425753E+00 -Si - Al: 4.2387345271E+00 -:MDSTEP: 4 -:MDTM: 13.95 -:TWIST: 0 -:TEL: 1000 -:TIO: 994.944318354926 -:TEN: -3.2422581903E+00 -:KEN: 4.5949183764E-03 -:KENIG: 4.7262017585E-03 -:FEN: -3.2468531086E+00 -:UEN: -3.2459523863E+00 -:TSEN: -9.0072231195E-04 -:NPT_NP_HAMIL: 4.0274804297E-06 -:R: - 1.0795248655E-01 1.3321406778E-01 1.3863503018E-01 - 5.2693199870E+00 5.2640354370E+00 1.4132086677E-01 - 1.0451536856E+01 1.0415225112E+01 1.1296765038E-01 - 9.6828313726E-02 5.2601218701E+00 5.2633360839E+00 - 5.2778233180E+00 1.0438569117E+01 5.2775878217E+00 - 1.0423455112E+01 1.5598731905E+01 5.2766901720E+00 - 8.0906871322E-02 1.0415097800E+01 1.0458559882E+01 - 5.2694782467E+00 1.5599800751E+01 1.0462902357E+01 - 1.0445013953E+01 2.0740403439E+01 1.0454461219E+01 - 5.2017583243E+00 1.0850076800E-01 5.2113047222E+00 - 1.0377648257E+01 5.2699446880E+00 5.2219611394E+00 - 1.5541720382E+01 1.0414356333E+01 5.2474684274E+00 - 5.2359807813E+00 5.2630260173E+00 1.0400794497E+01 - 1.0403946672E+01 1.0436452998E+01 1.0385966446E+01 - 1.5514439366E+01 1.5605530156E+01 1.0377504511E+01 - 5.2192434917E+00 1.0406515642E+01 1.5556368236E+01 - 1.0365971225E+01 1.5615644553E+01 1.5557425017E+01 - 1.5533517442E+01 2.0756880876E+01 1.5543634388E+01 - 2.5864261081E+00 2.5862852980E+00 2.5873349344E+00 - 7.7331554075E+00 7.7408932986E+00 2.5775327765E+00 - 1.2911262888E+01 1.2886667107E+01 2.5555581589E+00 - 2.5739045154E+00 7.7311131393E+00 7.7256897937E+00 - 7.7372712227E+00 1.2888464803E+01 7.7435814034E+00 - 1.2888452640E+01 1.8059596335E+01 7.7302241117E+00 - 2.5885044190E+00 1.2917720147E+01 1.2913528189E+01 - 7.7148337113E+00 1.8063156166E+01 1.2907160153E+01 - 1.2911106040E+01 2.3216842486E+01 1.2889659677E+01 - 7.6902272859E+00 2.5693047244E+00 7.7050557671E+00 - 1.2862862668E+01 7.7336606094E+00 7.6926780795E+00 - 1.8001138980E+01 1.2909410954E+01 7.6991499070E+00 - 7.6858141121E+00 7.7345920700E+00 1.2849357321E+01 - 1.2844718384E+01 1.2876166731E+01 1.2818980714E+01 - 1.8017365502E+01 1.8071516947E+01 1.2862912540E+01 - 7.7003574163E+00 1.2905986082E+01 1.8020543004E+01 - 1.2856668037E+01 1.8078250721E+01 1.8017446549E+01 - 1.8004260401E+01 2.3227940870E+01 1.8018507385E+01 -:V: - -1.2294318166E-05 4.9847933741E-04 2.9412577495E-04 - 1.8301875071E-05 -8.7149643461E-05 3.4836411700E-04 - 4.3798849124E-04 -2.9329699651E-04 -2.2362249266E-04 - -2.3659551455E-04 -7.2265264341E-05 -3.2087694673E-04 - 1.8955252881E-04 3.0269549778E-04 -3.3681058412E-05 - -1.2823354232E-04 2.7736848925E-04 -5.1999466832E-05 - -5.5676127511E-04 -3.8909016256E-04 1.7379033326E-04 - 2.1545634266E-05 1.1151763246E-04 2.6063868309E-04 - 3.0641568758E-04 -3.0793075738E-04 9.0892816340E-05 - -3.1137603698E-04 -1.4485082785E-06 -4.3118191185E-04 - 1.1645679328E-05 3.0551140915E-05 -2.1644244651E-04 - 6.5591760906E-05 -3.1204595396E-04 2.9783290196E-04 - 3.7808348293E-04 -1.5418619699E-05 2.5953880514E-04 - 5.4144240884E-04 2.5779559021E-04 -3.9642787751E-05 - -4.8432755231E-04 4.1376944045E-04 -2.0939130748E-04 - 4.1327185350E-05 -5.6395977178E-04 -4.4974483831E-05 - -2.2327870193E-04 4.2977380137E-04 -2.4063325214E-05 - -9.9522944888E-05 2.3103781876E-05 -3.0177195417E-04 - 1.2784585723E-04 1.2769723839E-04 1.4628159579E-04 - -1.3665899787E-04 2.2135589451E-05 -5.1389949150E-05 - 2.0032313405E-04 -2.9325001930E-04 -4.9425014063E-04 - -1.2473781856E-04 -8.1597089783E-05 -1.9327623923E-04 - -5.3911174253E-05 -1.3181901829E-04 1.6780811711E-04 - -2.6009386268E-04 6.4484022507E-05 -1.0199577935E-04 - 1.6930491797E-04 2.3887614927E-04 1.5211325739E-04 - -5.0607983679E-04 -5.1004005499E-05 2.3970639131E-05 - 1.9680394037E-04 -2.0721029334E-04 -3.2895287420E-04 - 2.9457468256E-05 -2.1684889406E-04 3.2846741796E-04 - 2.8742821617E-04 -1.2598540154E-04 7.9235911887E-05 - -1.7881474504E-04 1.6373970894E-04 2.0996557606E-04 - -5.9129902371E-05 -1.2573161375E-05 1.0901879025E-04 - -7.8089742669E-05 -3.8100726822E-04 -5.0265803740E-04 - 1.4793552118E-04 3.0274925458E-04 3.8208313914E-04 - 2.3376416645E-04 7.2238061554E-07 1.1862362492E-04 - 1.6274556491E-04 2.5119723446E-04 5.6451305309E-05 - -1.1594067751E-04 1.4869704374E-05 7.8024865699E-05 -:F: - -1.2230853944E-02 -9.2243953338E-03 -1.3557725717E-02 - -1.2220012292E-02 -8.6302032136E-03 -1.3306579939E-02 - -1.4055936612E-02 -9.3503700153E-03 -1.2827172343E-02 - -1.1265466605E-02 -7.9028374145E-03 -1.0743507365E-02 - -1.3887476085E-02 -9.2783372342E-03 -1.2745040744E-02 - -1.1841552246E-02 -1.1304535022E-02 -1.3945630495E-02 - -5.9400726941E-03 -6.0552496913E-03 -1.2222844459E-02 - -1.2553151970E-02 -1.0713120671E-02 -1.6443774937E-02 - -1.4441262182E-02 -9.6797541522E-03 -1.3315264354E-02 - -2.4529740023E-03 -1.2337267749E-02 -2.5173189105E-03 - -5.7362624440E-03 -1.3042839646E-02 -4.0292157503E-03 - -5.5522817669E-03 -1.2054704431E-02 -6.2559428589E-03 - -8.1496755846E-03 -1.3554342456E-02 -8.1262014935E-03 - -1.0308209745E-02 -1.7527163422E-02 -8.1974112842E-03 - -2.5308251101E-03 -1.1556929291E-02 -2.7081646599E-03 - -3.5989200682E-03 -1.1495307420E-02 -4.8955525360E-03 - -2.5818577939E-03 -1.4518547139E-02 -7.1343974118E-03 - -3.9496868839E-03 -1.3543629473E-02 -4.1834189924E-03 - 5.5339203657E-03 1.3955084521E-02 5.7991807537E-03 - 6.8270390926E-03 1.5081447719E-02 6.4434382187E-03 - 6.1601842807E-03 1.4543146436E-02 9.1231162863E-03 - 6.4544206751E-03 1.3948781267E-02 7.5705840210E-03 - 5.8067063451E-03 1.4963782609E-02 8.0906704470E-03 - 5.8082699303E-03 1.4714520208E-02 6.4478522052E-03 - 2.9959621271E-03 1.0706598042E-02 4.7901868455E-03 - 8.1809078426E-03 1.5856671975E-02 6.7123495597E-03 - 4.1996254586E-03 1.2766138605E-02 7.6240816518E-03 - 1.0167066906E-02 7.5098416971E-03 8.8888524039E-03 - 1.0183839358E-02 7.2345935142E-03 1.1694991795E-02 - 1.1931355273E-02 8.1943606458E-03 1.2407294184E-02 - 1.3168148173E-02 1.1516407462E-02 1.1310390418E-02 - 1.3998069851E-02 1.3276069713E-02 1.8031296593E-02 - 9.0584759228E-03 6.5462022359E-03 8.9947730277E-03 - 9.6837640694E-03 7.1296494245E-03 9.6855083911E-03 - 1.1824731220E-02 7.0789600854E-03 1.1365659490E-02 - 1.1313991139E-02 6.7472776127E-03 1.2174937960E-02 -:LATVEC_SCALE: 3.0962203447E+01 3.0962203447E+01 2.0641468965E+01 -:STRIO: - -6.8090003746E-01 4.8142180017E-02 -9.4012503427E-02 - 4.8142180017E-02 -6.7384290234E-01 -1.3051639601E-01 - -9.4012503427E-02 -1.3051639601E-01 -6.1665789484E-01 -:STRESS: - -1.5686455687E+01 -5.1556720987E+00 -3.9751075252E+00 - -5.1556720987E+00 -8.6956196287E+00 -4.6902445173E+00 - -3.9751075252E+00 -4.6902445173E+00 -1.5383331575E+01 -:PRESIO: 6.5713361155E-01 -:PRES: 1.3255135630E+01 -:PRESIG: 6.7458523495E-01 -:MIND: -Si - Si: 7.1888418027E+00 -Al - Al: 7.2004059542E+00 -Si - Al: 4.2224552185E+00 -:MDSTEP: 5 -:MDTM: 10.01 -:TWIST: 0 -:TEL: 1000 -:TIO: 993.206108979272 -:TEN: -3.2422557896E+00 -:KEN: 4.5868908616E-03 -:KENIG: 4.7179448862E-03 -:FEN: -3.2468426804E+00 -:UEN: -3.2459422541E+00 -:TSEN: -9.0042633269E-04 -:NPT_NP_HAMIL: 6.0459887700E-06 -:R: - 1.0768870538E-01 1.4142176182E-01 1.4343740007E-01 - 5.2698065446E+00 5.2627955275E+00 1.4702244685E-01 - 1.0459205000E+01 1.0410812627E+01 1.0920306260E-01 - 9.2856586153E-02 5.2591320272E+00 5.2582162424E+00 - 5.2811358643E+00 1.0444022852E+01 5.2772115534E+00 - 1.0421761790E+01 1.5603999403E+01 5.2760042406E+00 - 7.1663551962E-02 1.0409117379E+01 1.0461865210E+01 - 5.2700167208E+00 1.5602326336E+01 1.0467622818E+01 - 1.0450501966E+01 2.0736234813E+01 1.0456388413E+01 - 5.1968371533E+00 1.0841596118E-01 5.2044006589E+00 - 1.0378300661E+01 5.2706296232E+00 5.2186038150E+00 - 1.5543510659E+01 1.0409619020E+01 5.2526125713E+00 - 5.2424425474E+00 5.2629470100E+00 1.0405538287E+01 - 1.0413344949E+01 1.0441119360E+01 1.0385757170E+01 - 1.5507142370E+01 1.5613054303E+01 1.0374514542E+01 - 5.2201548833E+00 1.0397611331E+01 1.5556332650E+01 - 1.0362751526E+01 1.5623418245E+01 1.5557723628E+01 - 1.5532582959E+01 2.0758171580E+01 1.5539351554E+01 - 2.5886951807E+00 2.5885987675E+00 2.5899106702E+00 - 7.7312968205E+00 7.7417093443E+00 2.5768398203E+00 - 1.2915222892E+01 1.2882503089E+01 2.5475489564E+00 - 2.5719974118E+00 7.7302054602E+00 7.7228978761E+00 - 7.7367767751E+00 1.2886975181E+01 7.7467698110E+00 - 1.2884788890E+01 1.8061598809E+01 7.7289370137E+00 - 2.5914456870E+00 1.2922343877E+01 1.2916682717E+01 - 7.7068672238E+00 1.8063253633E+01 1.2908204090E+01 - 1.2914996877E+01 2.3214580761E+01 1.2884866351E+01 - 7.6911347795E+00 2.5658786754E+00 7.7109059922E+00 - 1.2868284519E+01 7.7319809812E+00 7.6944181131E+00 - 1.7999096179E+01 1.2912776669E+01 7.7030580178E+00 - 7.6852718203E+00 7.7348134874E+00 1.2851831812E+01 - 1.2844110635E+01 1.2870542629E+01 1.2811366836E+01 - 1.8020715775E+01 1.8077418239E+01 1.2869894483E+01 - 7.7046443366E+00 1.2906647485E+01 1.8023411753E+01 - 1.2860035008E+01 1.8083302019E+01 1.8019295440E+01 - 1.8003254988E+01 2.3229321991E+01 1.8020717911E+01 -:V: - -1.6274790969E-05 4.9641204697E-04 2.9028003725E-04 - 1.4381236602E-05 -9.0102769588E-05 3.4469949876E-04 - 4.3424637906E-04 -2.9686267157E-04 -2.2818497534E-04 - -2.4067652019E-04 -7.4955617362E-05 -3.2494420695E-04 - 1.8540757161E-04 3.0025032396E-04 -3.7867291240E-05 - -1.3230147736E-04 2.7422102282E-04 -5.6607927405E-05 - -5.5970842033E-04 -3.9176590447E-04 1.7015502465E-04 - 1.7523165156E-05 1.0825622160E-04 2.5579738711E-04 - 3.0230666725E-04 -3.1162995942E-04 8.6751396327E-05 - -3.1274303380E-04 -5.4434494416E-06 -4.3279028685E-04 - 9.8108942702E-06 2.6386790145E-05 -2.1814473892E-04 - 6.3915823009E-05 -3.1652125320E-04 2.9635680716E-04 - 3.7614232348E-04 -1.9833118057E-05 2.5738700707E-04 - 5.3910349462E-04 2.5259848146E-04 -4.2368407000E-05 - -4.8603813626E-04 4.1079140776E-04 -2.1065313395E-04 - 4.0238675110E-05 -5.6871781361E-04 -4.6641454449E-05 - -2.2452522216E-04 4.2586686804E-04 -2.6416277805E-05 - -1.0098425933E-04 1.8763667960E-05 -3.0368123320E-04 - 1.2994523149E-04 1.3263287957E-04 1.4850425821E-04 - -1.3461099628E-04 2.7256295251E-05 -4.9314181682E-05 - 2.0276688272E-04 -2.8889124090E-04 -4.9208704758E-04 - -1.2279338151E-04 -7.7048871954E-05 -1.9108201535E-04 - -5.2054521638E-05 -1.2702136878E-04 1.7084226207E-04 - -2.5861625521E-04 6.9559095686E-05 -1.0001168786E-04 - 1.7062574378E-04 2.4292226210E-04 1.5400679142E-04 - -5.0425589013E-04 -4.5756823517E-05 2.6275720280E-05 - 1.9858082609E-04 -2.0329167813E-04 -3.2699040423E-04 - 3.2936319148E-05 -2.1471852636E-04 3.3206618390E-04 - 2.9138762761E-04 -1.2378047192E-04 8.3321060518E-05 - -1.7512503909E-04 1.6680129063E-04 2.1453131952E-04 - -5.4803267929E-05 -8.7171819744E-06 1.1302922055E-04 - -7.3518465886E-05 -3.7723684189E-04 -4.9750983839E-04 - 1.5125907219E-04 3.0551158876E-04 3.8581628664E-04 - 2.3745634239E-04 3.1252239904E-06 1.2210442054E-04 - 1.6702815130E-04 2.5404411535E-04 6.0383578083E-05 - -1.1234317329E-04 1.7169796147E-05 8.2269447391E-05 -:F: - -1.2306630203E-02 -9.5353752499E-03 -1.3914457927E-02 - -1.2278043260E-02 -8.7323734909E-03 -1.3595946525E-02 - -1.4686958707E-02 -9.6574771297E-03 -1.2978233161E-02 - -1.0960778989E-02 -7.7945388284E-03 -1.0192077791E-02 - -1.4454101300E-02 -9.6081483013E-03 -1.2864521216E-02 - -1.1712913114E-02 -1.2266643494E-02 -1.4460021083E-02 - -4.1630014400E-03 -5.0140879466E-03 -1.1935360174E-02 - -1.2995833079E-02 -1.1255093845E-02 -1.7479108206E-02 - -1.5452397067E-02 -9.8168688146E-03 -1.3311123309E-02 - -1.5106264251E-03 -1.2019135549E-02 -1.4785202224E-03 - -5.8794092316E-03 -1.2902115957E-02 -3.4945405149E-03 - -5.5901605044E-03 -1.1553900082E-02 -6.4914991116E-03 - -9.0406737952E-03 -1.3626927946E-02 -8.9553486316E-03 - -1.2006889460E-02 -1.8966716948E-02 -9.1580586884E-03 - -1.5596397153E-03 -1.0973185906E-02 -1.7934424434E-03 - -3.3219803256E-03 -1.0574132585E-02 -4.3545501520E-03 - -1.9700529336E-03 -1.4581691982E-02 -7.2871353140E-03 - -3.7218418245E-03 -1.3258467521E-02 -3.4024593656E-03 - 5.4481752147E-03 1.4197843126E-02 5.7040155131E-03 - 7.1517923334E-03 1.5647312462E-02 6.5947320056E-03 - 6.3116412421E-03 1.4947319759E-02 1.0097598878E-02 - 6.9135092317E-03 1.3911334245E-02 7.7639676900E-03 - 6.0310565894E-03 1.5204671803E-02 8.4876276965E-03 - 6.0673515989E-03 1.4912579799E-02 6.2524945204E-03 - 2.1071454132E-03 9.8663799543E-03 4.3987896642E-03 - 8.9555979790E-03 1.6691174429E-02 6.9698696625E-03 - 3.6339823428E-03 1.2549456494E-02 8.1557557096E-03 - 9.6871378776E-03 7.2308517290E-03 7.8664704542E-03 - 9.6604615302E-03 6.7980095135E-03 1.1637103994E-02 - 1.2029040244E-02 8.1110665179E-03 1.2538574688E-02 - 1.3916231953E-02 1.2253135654E-02 1.0793928895E-02 - 1.5119700344E-02 1.4629068023E-02 1.9831098633E-02 - 8.4788813334E-03 5.6866041959E-03 7.7264196796E-03 - 9.0620079443E-03 6.7209678094E-03 8.9405264404E-03 - 1.1851834178E-02 6.5987346415E-03 1.1176803948E-02 - 1.1186384025E-02 6.1803714187E-03 1.2210625764E-02 -:LATVEC_SCALE: 3.0963666322E+01 3.0963666322E+01 2.0642444215E+01 -:STRIO: - -6.8078105701E-01 4.9857011837E-02 -9.3832333936E-02 - 4.9857011837E-02 -6.7325835831E-01 -1.2992099844E-01 - -9.3832333936E-02 -1.2992099844E-01 -6.1702236723E-01 -:STRESS: - -1.5675330760E+01 -5.1423108772E+00 -3.9927953464E+00 - -5.1423108772E+00 -8.6867576941E+00 -4.6879110369E+00 - -3.9927953464E+00 -4.6879110369E+00 -1.5380382082E+01 -:PRESIO: 6.5702059418E-01 -:PRES: 1.3247490179E+01 -:PRESIG: 6.7331126578E-01 -:MIND: -Si - Si: 7.1773163798E+00 -Al - Al: 7.1927235602E+00 -Si - Al: 4.2064594962E+00 -:MDSTEP: 6 -:MDTM: 11.38 -:TWIST: 0 -:TEL: 1000 -:TIO: 992.323501288495 -:TEN: -3.2422476547E+00 -:KEN: 4.5828147437E-03 -:KENIG: 4.7137523079E-03 -:FEN: -3.2468304694E+00 -:UEN: -3.2459301815E+00 -:TSEN: -9.0028791102E-04 -:NPT_NP_HAMIL: 8.0633272419E-06 -:R: - 1.0735970378E-01 1.4959945919E-01 1.4817832755E-01 - 5.2702886717E+00 5.2615659932E+00 1.5266645368E-01 - 1.0466931972E+01 1.0406456777E+01 1.0536140775E-01 - 8.8817906547E-02 5.2581581247E+00 5.2530897488E+00 - 5.2844391473E+00 1.0449557175E+01 5.2768257635E+00 - 1.0420120658E+01 1.5609391670E+01 5.2752995081E+00 - 6.2376942888E-02 1.0403214705E+01 1.0465233806E+01 - 5.2705470500E+00 1.5604975602E+01 1.0472380305E+01 - 1.0456039463E+01 2.0732240287E+01 1.0458368197E+01 - 5.1919555347E+00 1.0826790284E-01 5.1975317208E+00 - 1.0379041502E+01 5.2713072679E+00 5.2152793748E+00 - 1.5545452510E+01 1.0404927418E+01 5.2577940444E+00 - 5.2489310050E+00 5.2628549428E+00 1.0410364040E+01 - 1.0422819955E+01 1.0445814360E+01 1.0385616844E+01 - 1.5499996619E+01 1.5620715572E+01 1.0371626218E+01 - 5.2211101857E+00 1.0388747986E+01 1.5556451078E+01 - 1.0359631849E+01 1.5631310466E+01 1.5558161373E+01 - 1.5531803480E+01 2.0759631124E+01 1.5535217599E+01 - 2.5910294669E+00 2.5910262692E+00 2.5925537825E+00 - 7.7295618211E+00 7.7427027156E+00 2.5762113276E+00 - 1.2919374666E+01 1.2878559355E+01 2.5396060992E+00 - 2.5701536225E+00 7.7294612374E+00 7.7202306535E+00 - 7.7364029609E+00 1.2885713643E+01 7.7501013449E+00 - 1.2881297192E+01 1.8063895000E+01 7.7277698198E+00 - 2.5944351868E+00 1.2927180818E+01 1.2920016479E+01 - 7.6990196566E+00 1.8063650237E+01 1.2909436492E+01 - 1.2919064411E+01 2.3212648280E+01 1.2880254035E+01 - 7.6921860542E+00 2.5625140488E+00 7.7169017658E+00 - 1.2873919706E+01 7.7304234015E+00 7.6963147890E+00 - 1.7997320769E+01 1.2916342742E+01 7.7071330111E+00 - 7.6848933630E+00 7.7351918493E+00 1.2854518796E+01 - 1.2843732093E+01 1.2865133451E+01 1.2803991470E+01 - 1.8024326663E+01 1.8083571274E+01 1.2877082698E+01 - 7.7090796964E+00 1.2907495047E+01 1.8026542580E+01 - 1.2863622566E+01 1.8088608197E+01 1.8021416403E+01 - 1.8002514774E+01 2.3231005671E+01 1.8023207134E+01 -:V: - -2.0306311233E-05 4.9470804628E-04 2.8658273577E-04 - 1.0444476765E-05 -9.3182494410E-05 3.4125714184E-04 - 4.3070039269E-04 -3.0081870134E-04 -2.3302505582E-04 - -2.4489798486E-04 -7.7689330541E-05 -3.2915171508E-04 - 1.8124298494E-04 2.9797564782E-04 -4.2139735419E-05 - -1.3646429593E-04 2.7101266065E-04 -6.1449424000E-05 - -5.6261787328E-04 -3.9448262565E-04 1.6676372054E-04 - 1.3362675506E-05 1.0491261775E-04 2.5084931833E-04 - 2.9814476867E-04 -3.1567880295E-04 8.2681864638E-05 - -3.1410458202E-04 -9.3516408001E-06 -4.3447625322E-04 - 7.9339111240E-06 2.2281376623E-05 -2.1988503972E-04 - 6.2283428965E-05 -3.2114636485E-04 2.9508075743E-04 - 3.7426311919E-04 -2.4302208344E-05 2.5520422557E-04 - 5.3671803659E-04 2.4715965291E-04 -4.5452878296E-05 - -4.8789888805E-04 4.0838289890E-04 -2.1182155306E-04 - 3.9274910094E-05 -5.7372896561E-04 -4.8181982535E-05 - -2.2578953547E-04 4.2233160682E-04 -2.8850264026E-05 - -1.0247141720E-04 1.4521570587E-05 -3.0563027411E-04 - 1.3214452609E-04 1.3778965123E-04 1.5084157226E-04 - -1.3257518087E-04 3.2607860353E-05 -4.7228284314E-05 - 2.0546040089E-04 -2.8465743100E-04 -4.9005506058E-04 - -1.2080494420E-04 -7.2573509942E-05 -1.8899730318E-04 - -5.0166312341E-05 -1.2224932911E-04 1.7418038241E-04 - -2.5729191923E-04 7.4780927587E-05 -9.8182574761E-05 - 1.7181205836E-04 2.4692626806E-04 1.5591939083E-04 - -5.0264287219E-04 -4.0256953700E-05 2.8698920378E-05 - 2.0035988710E-04 -1.9962757503E-04 -3.2515265420E-04 - 3.6294232432E-05 -2.1287947943E-04 3.3564453994E-04 - 2.9545737962E-04 -1.2183372879E-04 8.7476937078E-05 - -1.7155783807E-04 1.7000118159E-04 2.1935708160E-04 - -5.0264210611E-05 -4.6103071380E-06 1.1698367512E-04 - -6.8625852558E-05 -3.7335673167E-04 -4.9221129238E-04 - 1.5453962524E-04 3.0828093328E-04 3.8949733561E-04 - 2.4117390681E-04 5.3999381467E-06 1.2545930516E-04 - 1.7148988787E-04 2.5697744265E-04 6.4320289168E-05 - -1.0888497521E-04 1.9301417309E-05 8.6615755819E-05 -:F: - -1.2371402440E-02 -9.8425582337E-03 -1.4246612419E-02 - -1.2315120669E-02 -8.8221123156E-03 -1.3871558253E-02 - -1.5302636607E-02 -9.9571815784E-03 -1.3113403389E-02 - -1.0641142627E-02 -7.6840740997E-03 -9.6247375876E-03 - -1.5002397326E-02 -9.9267135944E-03 -1.2974622343E-02 - -1.1576984277E-02 -1.3208600565E-02 -1.4944266614E-02 - -2.3830419622E-03 -3.9675443713E-03 -1.1685864619E-02 - -1.3430443798E-02 -1.1793031084E-02 -1.8503108781E-02 - -1.6446307553E-02 -9.9396523317E-03 -1.3282622640E-02 - -5.6301337018E-04 -1.1716511905E-02 -4.3336864036E-04 - -6.0139634212E-03 -1.2749465059E-02 -2.9589156924E-03 - -5.6134327897E-03 -1.1041231393E-02 -6.7214867238E-03 - -9.9171910892E-03 -1.3698665646E-02 -9.7704154837E-03 - -1.3728313396E-02 -2.0420270133E-02 -1.0155811214E-02 - -5.9720791847E-04 -1.0406634130E-02 -8.8088038717E-04 - -3.0615229239E-03 -9.6465885183E-03 -3.8144300852E-03 - -1.3688963732E-03 -1.4621767389E-02 -7.4170167921E-03 - -3.4949450025E-03 -1.2961789680E-02 -2.6108884072E-03 - 5.3449817975E-03 1.4433458130E-02 5.6002869248E-03 - 7.4677930624E-03 1.6199191374E-02 6.7372409759E-03 - 6.4673018619E-03 1.5337200876E-02 1.1045517355E-02 - 7.3535025751E-03 1.3867051673E-02 7.9471728298E-03 - 6.2482701592E-03 1.5430365256E-02 8.8750650495E-03 - 6.3187663006E-03 1.5095484805E-02 6.0365563058E-03 - 1.2360517389E-03 9.0312161095E-03 4.0319663796E-03 - 9.7249806243E-03 1.7515718558E-02 7.2299187979E-03 - 3.0441960136E-03 1.2300775166E-02 8.6912496745E-03 - 9.1946912281E-03 6.9579579064E-03 6.8351837811E-03 - 9.1228747752E-03 6.3557619412E-03 1.1573304703E-02 - 1.2113603579E-02 8.0211058140E-03 1.2650280867E-02 - 1.4646995853E-02 1.2973907145E-02 1.0266750993E-02 - 1.6282063096E-02 1.5994544070E-02 2.1637360400E-02 - 7.9048052027E-03 4.8437146705E-03 6.4543653083E-03 - 8.4446151720E-03 6.3204273316E-03 8.2001300506E-03 - 1.1866471704E-02 6.1147702744E-03 1.0971665405E-02 - 1.1045998801E-02 5.6117409265E-03 1.2225994271E-02 -:LATVEC_SCALE: 3.0965485734E+01 3.0965485734E+01 2.0643657156E+01 -:STRIO: - -6.8108482569E-01 5.1853417904E-02 -9.3619835140E-02 - 5.1853417904E-02 -6.7369049846E-01 -1.2942702230E-01 - -9.3619835140E-02 -1.2942702230E-01 -6.1791621830E-01 -:STRESS: - -1.5660213675E+01 -5.1245858015E+00 -4.0047888297E+00 - -5.1245858015E+00 -8.6778814063E+00 -4.6819975694E+00 - -4.0047888297E+00 -4.6819975694E+00 -1.5374528672E+01 -:PRESIO: 6.5756384748E-01 -:PRES: 1.3237541251E+01 -:PRESIG: 6.7259435998E-01 -:MIND: -Si - Si: 7.1659467450E+00 -Al - Al: 7.1851958777E+00 -Si - Al: 4.1907584366E+00 -:MDSTEP: 7 -:MDTM: 10.39 -:TWIST: 0 -:TEL: 1000 -:TIO: 992.481719869189 -:TEN: -3.2422329735E+00 -:KEN: 4.5835454394E-03 -:KENIG: 4.7145038805E-03 -:FEN: -3.2468165190E+00 -:UEN: -3.2459162149E+00 -:TSEN: -9.0030407262E-04 -:NPT_NP_HAMIL: 1.0053392122E-05 -:R: - 1.0696461538E-01 1.5775290427E-01 1.5286017541E-01 - 5.2707648614E+00 5.2603435153E+00 1.5825639249E-01 - 1.0474718294E+01 1.0402148674E+01 1.0143817978E-01 - 8.4710054981E-02 5.2571981671E+00 5.2479531716E+00 - 5.2877315011E+00 1.0455172248E+01 5.2764277396E+00 - 1.0418527640E+01 1.5614903819E+01 5.2745709417E+00 - 1.5536874952E+01 2.5881213797E+01 1.0468666826E+01 - 5.2710656344E+00 1.5607743302E+01 1.0477170360E+01 - 1.0461622904E+01 2.0728409172E+01 1.0460399240E+01 - 5.1871124461E+00 1.0805786416E-01 5.1906955654E+00 - 1.0379867565E+01 5.2719773021E+00 5.2119859976E+00 - 1.5547542888E+01 1.0400276647E+01 5.2630147500E+00 - 5.2554457732E+00 5.2627475737E+00 1.0415268627E+01 - 1.0432367966E+01 1.0450531170E+01 1.0385536766E+01 - 1.5492995998E+01 1.5628519268E+01 1.0368838625E+01 - 5.2221100705E+00 1.0379919106E+01 1.5556721814E+01 - 1.0356609402E+01 1.5639323431E+01 1.5558733213E+01 - 1.5531174808E+01 2.0761256058E+01 1.5531228242E+01 - 2.5934298656E+00 2.5935708107E+00 2.5952654567E+00 - 7.7279483668E+00 7.7438753387E+00 2.5756468434E+00 - 1.2923719167E+01 1.2874830810E+01 2.5317269086E+00 - 2.5683732306E+00 7.7288774442E+00 7.7176844925E+00 - 7.7361484288E+00 1.2884676671E+01 7.7535790682E+00 - 1.2877971960E+01 1.8066482895E+01 7.7267180371E+00 - 2.5974700940E+00 1.2932227096E+01 1.2923526733E+01 - 7.6912858676E+00 1.8064345807E+01 1.2910856205E+01 - 1.2923305325E+01 2.3211035136E+01 1.2875817723E+01 - 7.6933771957E+00 2.5592055556E+00 7.7230407164E+00 - 1.2879766760E+01 7.7289817631E+00 7.6983673925E+00 - 1.7995806394E+01 1.2920108246E+01 7.7113771781E+00 - 7.6846803826E+00 7.7357294027E+00 1.2857414158E+01 - 1.2843585284E+01 1.2859938180E+01 1.2796854330E+01 - 1.8028193067E+01 1.8089971749E+01 1.2884473034E+01 - 7.7136620053E+00 1.2908523573E+01 1.8029929021E+01 - 1.2867430460E+01 1.8094166179E+01 1.8023805056E+01 - 1.8002033093E+01 2.3232983468E+01 1.8025972260E+01 -:V: - -2.4390639775E-05 4.9331612854E-04 2.8300637940E-04 - 6.4902050991E-06 -9.6381215792E-05 3.3800116798E-04 - 4.2730572085E-04 -3.0514036130E-04 -2.3812338063E-04 - -2.4923803640E-04 -8.0462794824E-05 -3.3346862575E-04 - 1.7703860053E-04 2.9584111794E-04 -4.6499000163E-05 - -1.4071345193E-04 2.6771618753E-04 -6.6517408463E-05 - -5.6543610802E-04 -3.9720316559E-04 1.6358182405E-04 - 9.0574552420E-06 1.0147108621E-04 2.4576318535E-04 - 2.9389736743E-04 -3.2004881262E-04 7.8676613068E-05 - -3.1542920022E-04 -1.3183838656E-05 -4.3619652271E-04 - 6.0131855616E-06 1.8229341266E-05 -2.2164376037E-04 - 6.0690163426E-05 -3.2589335878E-04 2.9397475446E-04 - 3.7240906221E-04 -2.8831331137E-05 2.5296484403E-04 - 5.3421920691E-04 2.4143860920E-04 -4.8910403065E-05 - -4.8986651805E-04 4.0649423856E-04 -2.1287730826E-04 - 3.8425248338E-05 -5.7894225774E-04 -4.9593716262E-05 - -2.2705428146E-04 4.1912722602E-04 -3.1359573279E-05 - -1.0397698173E-04 1.0372489864E-05 -3.0758794813E-04 - 1.3442861314E-04 1.4316106405E-04 1.5327979264E-04 - -1.3053731321E-04 3.8192651669E-05 -4.5126606319E-05 - 2.0838978271E-04 -2.8051710440E-04 -4.8810975068E-04 - -1.1876284522E-04 -6.8158117754E-05 -1.8700282876E-04 - -4.8240314663E-05 -1.1748703943E-04 1.7780849961E-04 - -2.5609525492E-04 8.0146629937E-05 -9.6502607527E-05 - 1.7285386875E-04 2.5087158513E-04 1.5784686311E-04 - -5.0118893198E-04 -3.4492856679E-05 3.1242922718E-05 - 2.0211563623E-04 -1.9620268088E-04 -3.2340216901E-04 - 3.9528841206E-05 -2.1130564105E-04 3.3917141676E-04 - 2.9961008794E-04 -1.2013204641E-04 9.1700284536E-05 - -1.6809403949E-04 1.7332594444E-04 2.2442336636E-04 - -4.5504517421E-05 -2.4917770424E-07 1.2087342967E-04 - -6.3381189166E-05 -3.6931710844E-04 -4.8669972947E-04 - 1.5776892463E-04 3.1103631645E-04 3.9309152178E-04 - 2.4490036633E-04 7.5523267248E-06 1.2868252063E-04 - 1.7611763736E-04 2.5997518596E-04 6.8256421504E-05 - -1.0555354495E-04 2.1265214606E-05 9.1056214409E-05 -:F: - -1.2424447793E-02 -1.0146927513E-02 -1.4553694281E-02 - -1.2330593673E-02 -8.8984546774E-03 -1.4132697057E-02 - -1.5902477547E-02 -1.0246645611E-02 -1.3230472892E-02 - -1.0306687943E-02 -7.5712295154E-03 -9.0423788083E-03 - -1.5531265568E-02 -1.0234062779E-02 -1.3072955366E-02 - -1.1432209877E-02 -1.4132246620E-02 -1.5398306834E-02 - -5.9944115044E-04 -2.9151102453E-03 -1.1476626881E-02 - -1.3856179344E-02 -1.2326220317E-02 -1.9514358861E-02 - -1.7423795426E-02 -1.0047414318E-02 -1.3229890532E-02 - 3.8835259806E-04 -1.1430843153E-02 6.1696278755E-04 - -6.1408431552E-03 -1.2585359023E-02 -2.4225034073E-03 - -5.6230102126E-03 -1.0515959734E-02 -6.9471346846E-03 - -1.0777727643E-02 -1.3767810204E-02 -1.0570729713E-02 - -1.5469388643E-02 -2.1885155930E-02 -1.1187566069E-02 - 3.5671365342E-04 -9.8589086784E-03 2.7645580283E-05 - -2.8197186425E-03 -8.7137127027E-03 -3.2763190985E-03 - -7.7783236642E-04 -1.4640704663E-02 -7.5241179077E-03 - -3.2690080870E-03 -1.2653850300E-02 -1.8086191737E-03 - 5.2238020581E-03 1.4661184136E-02 5.4883422487E-03 - 7.7748689879E-03 1.6736451161E-02 6.8707524247E-03 - 6.6255552935E-03 1.5712630366E-02 1.1966591583E-02 - 7.7744666068E-03 1.3817096129E-02 8.1208369312E-03 - 6.4578925671E-03 1.5640236750E-02 9.2516237628E-03 - 6.5618661518E-03 1.5262201539E-02 5.7992359981E-03 - 3.8328219344E-04 8.2015786633E-03 3.6903176990E-03 - 1.0488102366E-02 1.8328766063E-02 7.4907893085E-03 - 2.4302711173E-03 1.2018762114E-02 9.2301923597E-03 - 8.6908624753E-03 6.6925984734E-03 5.7958762515E-03 - 8.5707885560E-03 5.9084502923E-03 1.1503957197E-02 - 1.2185384619E-02 7.9255836417E-03 1.2743327560E-02 - 1.5359630743E-02 1.3677944665E-02 9.7272010361E-03 - 1.7479885569E-02 1.7370591970E-02 2.3447760055E-02 - 7.3370120396E-03 4.0183982221E-03 5.1795181700E-03 - 7.8334357638E-03 5.9293276826E-03 7.4657963259E-03 - 1.1868616730E-02 5.6273148408E-03 1.0750587856E-02 - 1.0893836980E-02 5.0414992759E-03 1.2221056432E-02 -:LATVEC_SCALE: 3.0967654131E+01 3.0967654131E+01 2.0645102754E+01 -:STRIO: - -6.8168351458E-01 5.4122996101E-02 -9.3361238242E-02 - 5.4122996101E-02 -6.7501636626E-01 -1.2901804112E-01 - -9.3361238242E-02 -1.2901804112E-01 -6.1922550662E-01 -:STRESS: - -1.5641152892E+01 -5.1024613299E+00 -4.0110810639E+00 - -5.1024613299E+00 -8.6690009859E+00 -4.6724630614E+00 - -4.0110810639E+00 -4.6724630614E+00 -1.5365823143E+01 -:PRESIO: 6.5864179582E-01 -:PRES: 1.3225325673E+01 -:PRESIG: 6.7256029962E-01 -:MIND: -Si - Si: 7.1547296941E+00 -Al - Al: 7.1778233879E+00 -Si - Al: 4.1753638754E+00 -:MDSTEP: 8 -:MDTM: 9.22 -:TWIST: 0 -:TEL: 1000 -:TIO: 993.497806725819 -:TEN: -3.2422126240E+00 -:KEN: 4.5882379996E-03 -:KENIG: 4.7193305139E-03 -:FEN: -3.2468008620E+00 -:UEN: -3.2459003918E+00 -:TSEN: -9.0047020889E-04 -:NPT_NP_HAMIL: 1.1982813287E-05 -:R: - 1.0650258760E-01 1.6588635150E-01 1.5748449366E-01 - 5.2712333562E+00 5.2591248044E+00 1.6379474663E-01 - 1.0482562740E+01 1.0397879794E+01 9.7429520923E-02 - 8.0531504580E-02 5.2562500974E+00 5.2428037961E+00 - 5.2910104786E+00 1.0460866887E+01 5.2760146096E+00 - 1.0416978540E+01 1.5620529470E+01 5.2738134799E+00 - 1.5528760146E+01 2.5876712379E+01 1.0472164174E+01 - 5.2715685308E+00 1.5610623111E+01 1.0481987241E+01 - 1.0467247371E+01 2.0724730753E+01 1.0462479529E+01 - 5.1823075612E+00 1.0778695665E-01 5.1838909005E+00 - 1.0380775134E+01 5.2726390663E+00 5.2087222463E+00 - 1.5549777900E+01 1.0395662266E+01 5.2682754786E+00 - 5.2619851581E+00 5.2626223959E+00 1.0420247708E+01 - 1.0441983014E+01 1.0455261539E+01 1.0385507615E+01 - 1.5486135056E+01 1.5636468654E+01 1.0366150977E+01 - 5.2231547430E+00 1.0371119327E+01 1.5557142563E+01 - 1.0353681519E+01 1.5647457444E+01 1.5559433555E+01 - 1.5530692315E+01 2.0763041920E+01 1.5527379434E+01 - 2.5958967256E+00 2.5962349731E+00 2.5980463314E+00 - 7.7264544680E+00 7.7452287665E+00 2.5751459423E+00 - 1.2928256259E+01 1.2871312657E+01 2.5239099530E+00 - 2.5666565136E+00 7.7284510014E+00 7.7152559724E+00 - 7.7360116402E+00 1.2883860563E+01 7.7572052217E+00 - 1.2874807784E+01 1.8069359502E+01 7.7257770369E+00 - 2.6005470755E+00 1.2937477644E+01 1.2927209884E+01 - 7.6836618681E+00 1.8065339580E+01 1.2912461489E+01 - 1.2927715037E+01 2.3209730872E+01 1.2871552863E+01 - 7.6947038490E+00 2.5559484966E+00 7.7293191656E+00 - 1.2885822786E+01 7.7276499798E+00 7.7005746818E+00 - 1.7994546416E+01 1.2924071229E+01 7.7157918452E+00 - 7.6846343580E+00 7.7364280918E+00 1.2860512884E+01 - 1.2843672711E+01 1.2854956511E+01 1.2789956206E+01 - 1.8032308733E+01 1.8096613798E+01 1.2892059672E+01 - 7.7183888359E+00 1.2909727380E+01 1.8033563540E+01 - 1.2871457407E+01 1.8099971373E+01 1.8026456030E+01 - 1.8001802813E+01 2.3235245873E+01 1.8029009429E+01 -:V: - -2.8523753863E-05 4.9210926765E-04 2.7948148044E-04 - 2.5180171634E-06 -9.9674808793E-05 3.3484519938E-04 - 4.2395304291E-04 -3.0975334591E-04 -2.4342104208E-04 - -2.5363428831E-04 -8.3258621289E-05 -3.3781068608E-04 - 1.7274885810E-04 2.9377158731E-04 -5.0935883459E-05 - -1.4501622648E-04 2.6426338458E-04 -7.1793139397E-05 - -5.6801972569E-04 -3.9982705758E-04 1.6055040406E-04 - 4.6012684952E-06 9.7901646748E-05 2.4047185456E-04 - 2.8948752699E-04 -3.2466016741E-04 7.4717739514E-05 - -3.1663603917E-04 -1.6947309352E-05 -4.3783949586E-04 - 4.0467196997E-06 1.4224118660E-05 -2.2336606355E-04 - 5.9122695157E-05 -3.3068138865E-04 2.9296350177E-04 - 3.7048671413E-04 -3.3418948397E-05 2.5060494211E-04 - 5.3145875746E-04 2.3536000215E-04 -5.2745921379E-05 - -4.9182068277E-04 4.0501394576E-04 -2.1376782761E-04 - 3.7672991762E-05 -5.8421492865E-04 -5.0865991187E-05 - -2.2826597261E-04 4.1614926567E-04 -3.3932638833E-05 - -1.0547667495E-04 6.3118529441E-06 -3.0947427531E-04 - 1.3676037030E-04 1.4871612288E-04 1.5578052152E-04 - -1.2846380357E-04 4.4004865220E-05 -4.2997467020E-05 - 2.1150733653E-04 -2.7639723850E-04 -4.8613184078E-04 - -1.1663971989E-04 -6.3780956710E-05 -1.8505109576E-04 - -4.6263728471E-05 -1.1270275297E-04 1.8168349234E-04 - -2.5496182868E-04 8.5638354463E-05 -9.4952334094E-05 - 1.7371365131E-04 2.5470076339E-04 1.5975981102E-04 - -4.9976547833E-04 -2.8450143228E-05 3.3904098999E-05 - 2.0379019874E-04 -1.9297373927E-04 -3.2165221570E-04 - 4.2630216998E-05 -2.0993882187E-04 3.4256144227E-04 - 3.0376986339E-04 -1.1864474151E-04 9.5971907475E-05 - -1.6469007048E-04 1.7673427727E-04 2.2967425075E-04 - -4.0510820557E-05 4.3679415271E-06 1.2466842254E-04 - -5.7747152734E-05 -3.6501266772E-04 -4.8083940122E-04 - 1.6091280001E-04 3.1370731929E-04 3.9650127507E-04 - 2.4858001551E-04 9.5861950414E-06 1.3174697728E-04 - 1.8086907766E-04 2.6297366517E-04 7.2174620395E-05 - -1.0232139235E-04 2.3057261833E-05 9.5567234720E-05 -:F: - -1.2464331352E-02 -1.0448044993E-02 -1.4835609497E-02 - -1.2323596955E-02 -8.9601728784E-03 -1.4379436277E-02 - -1.6486423338E-02 -1.0525752377E-02 -1.3329767687E-02 - -9.9587549825E-03 -7.4569214317E-03 -8.4452845807E-03 - -1.6039647067E-02 -1.0529056411E-02 -1.3159572494E-02 - -1.1278046552E-02 -1.5036608617E-02 -1.5821139374E-02 - 1.1850978957E-03 -1.8578213060E-03 -1.1308681815E-02 - -1.4270998934E-02 -1.2852875244E-02 -2.0510607382E-02 - -1.8384339716E-02 -1.0138449930E-02 -1.3152816380E-02 - 1.3422611575E-03 -1.1164354366E-02 1.6708201746E-03 - -6.2603327533E-03 -1.2410367177E-02 -1.8858651753E-03 - -5.6179807684E-03 -9.9784738484E-03 -7.1680958619E-03 - -1.1621005485E-02 -1.3834003869E-02 -1.1354149548E-02 - -1.7225826225E-02 -2.3358011643E-02 -1.2248964473E-02 - 1.3005527186E-03 -9.3311122426E-03 9.3091792762E-04 - -2.5978093337E-03 -7.7758878610E-03 -2.7402267536E-03 - -1.9622694617E-04 -1.4639977651E-02 -7.6103393936E-03 - -3.0448803642E-03 -1.2335247305E-02 -9.9703270715E-04 - 5.0840785643E-03 1.4880273230E-02 5.3682126113E-03 - 8.0726569376E-03 1.7258589638E-02 6.9939445687E-03 - 6.7853885872E-03 1.6072852700E-02 1.2860214562E-02 - 8.1758280892E-03 1.3761363539E-02 8.2852217870E-03 - 6.6590045323E-03 1.5834677166E-02 9.6158142826E-03 - 6.7961945585E-03 1.5412204493E-02 5.5396879959E-03 - -4.4986254859E-04 7.3786815539E-03 3.3753182780E-03 - 1.1243407610E-02 1.9128470308E-02 7.7508749046E-03 - 1.7914368620E-03 1.1702864052E-02 9.7721380120E-03 - 8.1769334756E-03 6.4357920114E-03 4.7498461781E-03 - 8.0055178136E-03 5.4565591604E-03 1.1429305880E-02 - 1.2244881006E-02 7.8238464419E-03 1.2817770244E-02 - 1.6053126209E-02 1.4363798004E-02 9.1743129963E-03 - 1.8708299001E-02 1.8755479996E-02 2.5259792568E-02 - 6.7765712768E-03 3.2119050023E-03 3.9034503762E-03 - 7.2288835670E-03 5.5484540229E-03 6.7392252963E-03 - 1.1858702983E-02 5.1369427067E-03 1.0513705108E-02 - 1.0731240474E-02 4.4703851247E-03 1.2197015647E-02 -:LATVEC_SCALE: 3.0970162576E+01 3.0970162576E+01 2.0646775051E+01 -:STRIO: - -6.8223892374E-01 5.6637102488E-02 -9.3015682006E-02 - 5.6637102488E-02 -6.7690646734E-01 -1.2863985796E-01 - -9.3015682006E-02 -1.2863985796E-01 -6.2064527838E-01 -:STRESS: - -1.5618228245E+01 -5.0759154845E+00 -4.0116632401E+00 - -5.0759154845E+00 -8.6601440278E+00 -4.6592751153E+00 - -4.0116632401E+00 -4.6592751153E+00 -1.5354351612E+01 -:PRESIO: 6.5993022315E-01 -:PRES: 1.3210907961E+01 -:PRESIG: 6.7308527885E-01 -:MIND: -Si - Si: 7.1436638384E+00 -Al - Al: 7.1706080309E+00 -Si - Al: 4.1602911416E+00 -:MDSTEP: 9 -:MDTM: 9.18 -:TWIST: 0 -:TEL: 1000 -:TIO: 994.883637832858 -:TEN: -3.2421889033E+00 -:KEN: 4.5946381375E-03 -:KENIG: 4.7259135129E-03 -:FEN: -3.2467835415E+00 -:UEN: -3.2458827613E+00 -:TSEN: -9.0078014230E-04 -:NPT_NP_HAMIL: 1.3815869983E-05 -:R: - 1.0597288180E-01 1.7400168171E-01 1.6205154345E-01 - 5.2716923102E+00 5.2579069440E+00 1.6928239678E-01 - 1.0490461835E+01 2.5880143575E+01 1.5579833458E+01 - 7.6281923974E-02 5.2553120973E+00 5.2376404109E+00 - 5.2942727018E+00 1.0466638300E+01 5.2755835995E+00 - 1.0415469598E+01 1.5626260661E+01 5.2730223386E+00 - 1.5520775780E+01 2.5872447849E+01 1.0475724487E+01 - 5.2720516177E+00 1.5613607860E+01 1.0486823785E+01 - 1.0472906316E+01 2.0721195423E+01 1.0464606519E+01 - 5.1775419678E+00 1.0745619188E-01 5.1771184253E+00 - 1.0381760254E+01 5.2732916977E+00 5.2054876188E+00 - 1.5552153092E+01 1.0391081174E+01 5.2735755074E+00 - 5.2685456165E+00 5.2624768676E+00 1.0425295552E+01 - 1.0451656195E+01 1.0459995668E+01 1.0385519848E+01 - 1.5479410298E+01 1.5644564601E+01 1.0363563268E+01 - 5.2242440018E+00 1.0362345796E+01 1.5557710919E+01 - 1.0350846346E+01 1.5655710532E+01 1.5560256698E+01 - 1.5530351516E+01 2.0764983762E+01 1.5523668306E+01 - 2.5984296323E+00 2.5990206491E+00 2.6008962521E+00 - 7.7250785886E+00 7.7467642336E+00 2.5747083426E+00 - 1.2932984604E+01 1.2868001167E+01 2.5161559835E+00 - 2.5650041993E+00 7.7281790364E+00 7.7129423920E+00 - 7.7359911162E+00 1.2883261913E+01 7.7609810384E+00 - 1.2871800185E+01 1.8072521072E+01 7.7249423888E+00 - 2.6036620229E+00 1.2942926014E+01 1.2931061484E+01 - 7.6761459039E+00 1.8066630625E+01 1.2914250229E+01 - 1.2932287603E+01 2.3208725346E+01 1.2867456244E+01 - 7.6961612957E+00 2.5527391963E+00 7.7357316489E+00 - 1.2892083168E+01 7.7264223702E+00 7.7029348573E+00 - 1.7993534619E+01 1.2928228660E+01 7.7203770909E+00 - 7.6847568185E+00 7.7372896921E+00 1.2863809092E+01 - 1.2843997207E+01 1.2850189787E+01 1.2783300094E+01 - 1.8036666360E+01 1.8103489821E+01 1.2899834668E+01 - 7.7232565144E+00 1.2911100560E+01 1.8037437690E+01 - 1.2875701027E+01 1.8106017589E+01 1.8029363228E+01 - 1.8001816924E+01 2.3237782810E+01 1.8032313942E+01 -:V: - -3.2695858369E-05 4.9092860878E-04 2.7592273260E-04 - -1.4690712136E-06 -1.0302940486E-04 3.3168299958E-04 - 4.2050725993E-04 -3.1455899333E-04 -2.4883866908E-04 - -2.5800403986E-04 -8.6051790581E-05 -3.4206728241E-04 - 1.6832030876E-04 2.9167425323E-04 -5.5434173095E-05 - -1.4932640670E-04 2.6057110444E-04 -7.7248608526E-05 - -5.7018521347E-04 -4.0222475884E-04 1.5760205480E-04 - -8.3024009043E-09 9.4171036671E-05 2.3489672833E-04 - 2.8482231305E-04 -3.2940707523E-04 7.0785734723E-05 - -3.1762200650E-04 -2.0645666412E-05 -4.3926297702E-04 - 2.0337208373E-06 1.0261429504E-05 -2.2498068290E-04 - 5.7565358298E-05 -3.3540342308E-04 2.9195300400E-04 - 3.6837949183E-04 -3.8057419148E-05 2.4804611981E-04 - 5.2825569711E-04 2.2883808681E-04 -5.6956889884E-05 - -4.9360663328E-04 4.0380468159E-04 -2.1442545231E-04 - 3.6999256395E-05 -5.8936051389E-04 -5.1983409148E-05 - -2.2935438566E-04 4.1326752895E-04 -3.6554147032E-05 - -1.0693809982E-04 2.3380161562E-06 -3.1118707573E-04 - 1.3909134540E-04 1.5440919169E-04 1.5829284238E-04 - -1.2631417291E-04 5.0031074337E-05 -4.0828463328E-05 - 2.1474844597E-04 -2.7220985354E-04 -4.8397099936E-04 - -1.1440216425E-04 -5.9419728210E-05 -1.8308371215E-04 - -4.4222505571E-05 -1.0786093741E-04 1.8574662043E-04 - -2.5381117502E-04 9.1227896815E-05 -9.3507708731E-05 - 1.7434156861E-04 2.5833614965E-04 1.6161694548E-04 - -4.9821187830E-04 -2.2117698384E-05 3.6673968848E-05 - 2.0531008087E-04 -1.8988769884E-04 -3.1979590218E-04 - 4.5583151420E-05 -2.0870776485E-04 3.4570343491E-04 - 3.0783723236E-04 -1.1733455242E-04 1.0026271496E-04 - -1.6129400432E-04 1.8016999442E-04 2.3503420322E-04 - -3.5271140323E-05 9.2385659722E-06 1.2832648861E-04 - -5.1688132436E-05 -3.6031711054E-04 -4.7446715150E-04 - 1.6392379917E-04 3.1620037665E-04 3.9959956896E-04 - 2.5213733354E-04 1.1503082413E-05 1.3461443056E-04 - 1.8568602951E-04 2.6588909916E-04 7.6049374079E-05 - -9.9156530920E-05 2.4670533475E-05 1.0011550040E-04 -:F: - -1.2490113919E-02 -1.0746843131E-02 -1.5092036240E-02 - -1.2293394770E-02 -9.0066433253E-03 -1.4611185928E-02 - -1.7053804576E-02 -1.0791815154E-02 -1.3409785934E-02 - -9.5965155975E-03 -7.3412185054E-03 -7.8334267825E-03 - -1.6526677735E-02 -1.0811862306E-02 -1.3231839763E-02 - -1.1113465917E-02 -1.5922562248E-02 -1.6212735902E-02 - 2.9704879137E-03 -7.9594681651E-04 -1.1184540119E-02 - -1.4674097762E-02 -1.3370941832E-02 -2.1489929742E-02 - -1.9328291305E-02 -1.0212157660E-02 -1.3050797974E-02 - 2.2969284035E-03 -1.0917364072E-02 2.7265995838E-03 - -6.3735205943E-03 -1.2225582795E-02 -1.3492970535E-03 - -5.5989990919E-03 -9.4285849823E-03 -7.3855510824E-03 - -1.2446239160E-02 -1.3895746066E-02 -1.2121010345E-02 - -1.8993616861E-02 -2.4835530762E-02 -1.3336065172E-02 - 2.2341398204E-03 -8.8240510451E-03 1.8269537888E-03 - -2.3976944716E-03 -6.8336623813E-03 -2.2072767211E-03 - 3.7628319215E-04 -1.4620941558E-02 -7.6755307194E-03 - -2.8233248771E-03 -1.2007140727E-02 -1.7655232890E-04 - 4.9260061642E-03 1.5090077302E-02 5.2408866028E-03 - 8.3606003194E-03 1.7764243948E-02 7.1066391632E-03 - 6.9454285597E-03 1.6417037114E-02 1.3725574864E-02 - 8.5576693703E-03 1.3700181681E-02 8.4407192173E-03 - 6.8505737673E-03 1.6012989864E-02 9.9662159762E-03 - 7.0217322116E-03 1.5544797757E-02 5.2577116293E-03 - -1.2622684933E-03 6.5633572536E-03 3.0878400824E-03 - 1.1989238685E-02 1.9913541729E-02 8.0077722003E-03 - 1.1276158757E-03 1.1351607648E-02 1.0316324252E-02 - 7.6537868382E-03 6.1893309384E-03 3.6977141989E-03 - 7.4274902264E-03 5.0002817231E-03 1.1349665878E-02 - 1.2292581118E-02 7.7169056742E-03 1.2874406351E-02 - 1.6726433838E-02 1.5030778041E-02 8.6067300143E-03 - 1.9961756391E-02 2.0146341858E-02 2.7070205090E-02 - 6.2241990762E-03 2.4254276447E-03 2.6273286660E-03 - 6.6326757005E-03 5.1788777296E-03 6.0220776132E-03 - 1.1837135552E-02 4.6442733711E-03 1.0261697184E-02 - 1.0559262107E-02 3.8985440930E-03 1.2154499451E-02 -:LATVEC_SCALE: 3.0973001488E+01 3.0973001488E+01 2.0648667659E+01 -:STRIO: - -6.8232223518E-01 5.9352932577E-02 -9.2532312074E-02 - 5.9352932577E-02 -6.7894009159E-01 -1.2822340046E-01 - -9.2532312074E-02 -1.2822340046E-01 -6.2178666567E-01 -:STRESS: - -1.5591526392E+01 -5.0449242724E+00 -4.0065278030E+00 - -5.0449242724E+00 -8.6513382755E+00 -4.6424118476E+00 - -4.0065278030E+00 -4.6424118476E+00 -1.5340192625E+01 -:PRESIO: 6.6101633081E-01 -:PRES: 1.3194352431E+01 -:PRESIG: 6.7383884478E-01 -:MIND: -Si - Si: 7.1307413616E+00 -Al - Al: 7.1635541935E+00 -Si - Al: 4.1455607037E+00 -:MDSTEP: 10 -:MDTM: 7.62 -:TWIST: 0 -:TEL: 1000 -:TIO: 996.016917140147 -:TEN: -3.2421647469E+00 -:KEN: 4.5998719238E-03 -:KENIG: 4.7312968359E-03 -:FEN: -3.2467646188E+00 -:UEN: -3.2458633932E+00 -:TSEN: -9.0122553796E-04 -:NPT_NP_HAMIL: 1.5509855489E-05 -:R: - 1.0537494384E-01 1.8209832795E-01 1.6656030079E-01 - 5.2721399525E+00 5.2566875603E+00 1.7471861102E-01 - 1.0498410037E+01 2.5877512649E+01 1.5577226935E+01 - 7.1962292665E-02 5.2543827435E+00 5.2324635360E+00 - 5.2975139972E+00 1.0472482267E+01 5.2751322222E+00 - 1.0413997787E+01 1.5632088146E+01 5.2721932000E+00 - 1.5512925069E+01 2.5868416716E+01 1.0479345334E+01 - 5.2725107622E+00 1.5616689875E+01 1.0491671644E+01 - 1.0478591771E+01 2.0717795217E+01 1.0466777388E+01 - 5.1728183371E+00 1.0706653894E-01 5.1703810298E+00 - 1.0382818952E+01 5.2739342821E+00 5.2022827146E+00 - 1.5554663757E+01 1.0386531940E+01 5.2789126577E+00 - 5.2751218202E+00 5.2623085934E+00 1.0430405220E+01 - 1.0461375827E+01 1.0464722467E+01 1.0385563974E+01 - 1.5472820604E+01 1.5652805842E+01 1.0361076514E+01 - 5.2253773342E+00 1.0353598553E+01 1.5558424698E+01 - 1.0348103103E+01 1.5664078710E+01 1.5561197180E+01 - 1.5530148412E+01 2.0767076605E+01 1.5520093560E+01 - 2.6010274004E+00 2.6019289855E+00 2.6038142632E+00 - 7.7238197887E+00 7.7484827110E+00 2.5743339334E+00 - 1.2937901826E+01 1.2864893914E+01 2.5084680422E+00 - 2.5634175088E+00 7.7280589843E+00 7.7107419280E+00 - 7.7360855649E+00 1.2882877810E+01 7.7649068006E+00 - 1.2868945898E+01 1.8075963357E+01 7.7242100041E+00 - 2.6068100630E+00 1.2948564524E+01 1.2935076438E+01 - 7.6687386697E+00 1.8068218115E+01 1.2916220135E+01 - 1.2937015909E+01 2.3208009162E+01 1.2863526272E+01 - 7.6977445546E+00 2.5495750798E+00 7.7422709564E+00 - 1.2898541715E+01 7.7252938068E+00 7.7054456358E+00 - 1.7992765541E+01 1.2932576608E+01 7.7251317859E+00 - 7.6850494274E+00 7.7383158950E+00 1.2867296197E+01 - 1.2844562084E+01 1.2845641249E+01 1.2776891444E+01 - 1.8041257879E+01 1.8110590752E+01 1.2907788084E+01 - 7.7282601819E+00 1.2912637210E+01 1.8041542401E+01 - 1.2880157996E+01 1.8112297305E+01 1.8032520110E+01 - 1.8002068871E+01 2.3240584050E+01 1.8035880533E+01 -:V: - -3.6894497617E-05 4.8963827113E-04 2.7226067759E-04 - -5.4641766438E-06 -1.0641252245E-04 3.2842642663E-04 - 4.1685559254E-04 -3.1946768872E-04 -2.5430271852E-04 - -2.6227189812E-04 -8.8818610939E-05 -3.4613921553E-04 - 1.6371137594E-04 2.8947135266E-04 -5.9975193375E-05 - -1.5360020641E-04 2.5657090579E-04 -8.2854364411E-05 - -5.7177247240E-04 -4.0428256114E-04 1.5467839915E-04 - -4.7692799535E-06 9.0254221935E-05 2.2897535644E-04 - 2.7982564236E-04 -3.3419413413E-04 6.6868162837E-05 - -3.1829782601E-04 -2.4280121754E-05 -4.4034361578E-04 - -2.5038344855E-08 6.3408078254E-06 -2.2642502367E-04 - 5.6006338488E-05 -3.3996308338E-04 2.9086300076E-04 - 3.6598950624E-04 -4.2736096707E-05 2.4522327937E-04 - 5.2445673551E-04 2.2180414429E-04 -6.1538538260E-05 - -4.9509018278E-04 4.0274839048E-04 -2.1479204948E-04 - 3.6386871335E-05 -5.9421447286E-04 -5.2932124215E-05 - -2.3025843825E-04 4.1037280157E-04 -3.9207979986E-05 - -1.0833255708E-04 -1.5471825461E-06 -3.1263661415E-04 - 1.4137725354E-04 1.6019624233E-04 1.6077099981E-04 - -1.2405576293E-04 5.6254254873E-05 -3.8611076429E-05 - 2.1805484475E-04 -2.6788336371E-04 -4.8150089356E-04 - -1.1202390556E-04 -5.5058747767E-05 -1.8105223240E-04 - -4.2106782088E-05 -1.0293560227E-04 1.8994344484E-04 - -2.5257535158E-04 9.6885841335E-05 -9.2150429590E-05 - 1.7469528276E-04 2.6170852752E-04 1.6338284813E-04 - -4.9639188192E-04 -1.5491451965E-05 3.9542433750E-05 - 2.0660946049E-04 -1.8690359500E-04 -3.1774264602E-04 - 4.8371928234E-05 -2.0755126646E-04 3.4849891068E-04 - 3.1172291401E-04 -1.1617081426E-04 1.0454430146E-04 - -1.5786418619E-04 1.8358223182E-04 2.4043369528E-04 - -2.9780092746E-05 1.4356093933E-05 1.3180728865E-04 - -4.5177901642E-05 -3.5512535343E-04 -4.6744777670E-04 - 1.6675923389E-04 3.1843417855E-04 4.0227468644E-04 - 2.5550538802E-04 1.3303558036E-05 1.3725047415E-04 - 1.9051442980E-04 2.6864715605E-04 7.9855200846E-05 - -9.6034085060E-05 2.6097526241E-05 1.0466823666E-04 -:F: - -1.2500337533E-02 -1.1042167276E-02 -1.5322384989E-02 - -1.2239672408E-02 -9.0370109698E-03 -1.4826762715E-02 - -1.7603377985E-02 -1.1043891335E-02 -1.3470142005E-02 - -9.2216552750E-03 -7.2246830511E-03 -7.2088741981E-03 - -1.6991143087E-02 -1.1081183003E-02 -1.3289485124E-02 - -1.0937744500E-02 -1.6788912594E-02 -1.6571908100E-02 - 4.7533112017E-03 2.6896721315E-04 -1.1105198474E-02 - -1.5063066014E-02 -1.3878740728E-02 -2.2449174822E-02 - -2.0254006398E-02 -1.0268178289E-02 -1.2923441423E-02 - 3.2503730450E-03 -1.0691575875E-02 3.7809443046E-03 - -6.4809936222E-03 -1.2031713013E-02 -8.1412942014E-04 - -5.5664652217E-03 -8.8667068578E-03 -7.5988842310E-03 - -1.3250817969E-02 -1.3952279130E-02 -1.2868065351E-02 - -2.0766083058E-02 -2.6312163136E-02 -1.4443169618E-02 - 3.1547536595E-03 -8.3396416863E-03 2.7134018256E-03 - -2.2202042791E-03 -5.8884103765E-03 -1.6783457876E-03 - 9.3861202663E-04 -1.4584713224E-02 -7.7207798440E-03 - -2.6054522695E-03 -1.1669993961E-02 6.5066066392E-04 - 4.7493555916E-03 1.5289526149E-02 5.1063852776E-03 - 8.6382507916E-03 1.8252263130E-02 7.2079699545E-03 - 7.1042244518E-03 1.6744049651E-02 1.4561259543E-02 - 8.9193396308E-03 1.3634181253E-02 8.5873705876E-03 - 7.0320282498E-03 1.6175145839E-02 1.0301393778E-02 - 7.2377758037E-03 1.5658783622E-02 4.9528535625E-03 - -2.0524997141E-03 5.7572940572E-03 2.8293695201E-03 - 1.2723943555E-02 2.0680862483E-02 8.2597427108E-03 - 4.3914432391E-04 1.0965206563E-02 1.0862353806E-02 - 7.1233274788E-03 5.9543150078E-03 2.6416183645E-03 - 6.8377236637E-03 4.5406957759E-03 1.1265708416E-02 - 1.2328715461E-02 7.6048851158E-03 1.2913698620E-02 - 1.7378144286E-02 1.5676956570E-02 8.0240061400E-03 - 2.1233979016E-02 2.1539079192E-02 2.8873664453E-02 - 5.6817775798E-03 1.6605580485E-03 1.3535964246E-03 - 6.0459003074E-03 4.8218259583E-03 5.3160611139E-03 - 1.1803661053E-02 4.1500627841E-03 9.9950971447E-03 - 1.0379178157E-02 3.3273060913E-03 1.2093589891E-02 -:LATVEC_SCALE: 3.0976161246E+01 3.0976161246E+01 2.0650774164E+01 -:STRIO: - -6.8156816004E-01 6.2224845880E-02 -9.1871762375E-02 - 6.2224845880E-02 -6.8075551212E-01 -1.2771406639E-01 - -9.1871762375E-02 -1.2771406639E-01 -6.2231648767E-01 -:STRESS: - -1.5561112203E+01 -5.0094785695E+00 -3.9956727209E+00 - -5.0094785695E+00 -8.6425997166E+00 -4.6218628788E+00 - -3.9956727209E+00 -4.6218628788E+00 -1.5323403707E+01 -:PRESIO: 6.6154671994E-01 -:PRES: 1.3175705209E+01 -:PRESIG: 6.7439999872E-01 -:MIND: -Si - Si: 7.1139027043E+00 -Al - Al: 7.1566688457E+00 -Si - Al: 4.1311981371E+00 diff --git a/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.refout b/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.refout deleted file mode 100644 index f9ef5d0c..00000000 --- a/tests/Al18Si18_NPTNP/high_accuracy/Al18Si18_NPTNP.refout +++ /dev/null @@ -1,573 +0,0 @@ -*************************************************************************** -* SPARC (version June 24, 2024) * -* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * -* Distributed under GNU General Public License 3 (GPL) * -* Start time: Mon Jun 24 20:00:43 2024 * -*************************************************************************** - Input parameters -*************************************************************************** -LATVEC_SCALE: 30.96 30.96 20.64 -LATVEC: -0.500000000000000 0.500000000000000 0.000000000000000 -0.000000000000000 0.500000000000000 0.500000000000000 -0.500000000000000 0.000000000000000 0.500000000000000 -FD_GRID: 73 73 49 -FD_ORDER: 12 -BC: P P P -KPOINT_GRID: 1 1 1 -KPOINT_SHIFT: 0 0 0 -SPIN_TYP: 0 -ELEC_TEMP_TYPE: Fermi-Dirac -ELEC_TEMP: 1000 -EXCHANGE_CORRELATION: GGA_PBE -NSTATES: 80 -CHEB_DEGREE: 31 -CHEFSI_BOUND_FLAG: 0 -CALC_STRESS: 1 -TWTIME: 1E+09 -MD_FLAG: 1 -MD_METHOD: NPT_NP -MD_TIMESTEP: 0.4 -MD_NSTEP: 10 -ION_VEL_DSTR: 2 -ION_VEL_DSTR_RAND: 0 -ION_TEMP: 1000 -NPT_SCALE_VECS: 1 2 3 -NPT_SCALE_CONSTRAINTS: 123 -NPT_NP_QMASS: 500 -NPT_NP_BMASS: 0.05 -TARGET_PRESSURE: 12 GPa -MAXIT_SCF: 100 -MINIT_SCF: 2 -MAXIT_POISSON: 3000 -TOL_SCF: 5.00E-07 -POISSON_SOLVER: AAR -TOL_POISSON: 5.00E-09 -TOL_LANCZOS: 1.00E-02 -TOL_PSEUDOCHARGE: 5.00E-10 -MIXING_VARIABLE: potential -MIXING_PRECOND: kerker -TOL_PRECOND: 8.95E-05 -PRECOND_KERKER_KTF: 1 -PRECOND_KERKER_THRESH: 0.1 -MIXING_PARAMETER: 0.3 -MIXING_HISTORY: 7 -PULAY_FREQUENCY: 1 -PULAY_RESTART: 0 -REFERENCE_CUTOFF: 0.5 -RHO_TRIGGER: 4 -NUM_CHEFSI: 1 -FIX_RAND: 0 -VERBOSITY: 1 -PRINT_FORCES: 1 -PRINT_ATOMS: 1 -PRINT_EIGEN: 0 -PRINT_DENSITY: 0 -PRINT_MDOUT: 1 -PRINT_VELS: 1 -PRINT_RESTART: 1 -PRINT_RESTART_FQ: 1 -PRINT_ENERGY_DENSITY: 0 -OUTPUT_FILE: Al18Si18_NPTNP/temp_run/Al18Si18_NPTNP -*************************************************************************** - Cell -*************************************************************************** -Lattice vectors (Bohr): -15.480000000000000 15.480000000000000 0.000000000000000 -0.000000000000000 15.480000000000000 15.480000000000000 -10.320000000000000 0.000000000000000 10.320000000000000 -Volume: 4.9459714560E+03 (Bohr^3) -Density: 2.0040687695E-01 (amu/Bohr^3), 2.2457340241E+00 (g/cc) -*************************************************************************** - Parallelization -*************************************************************************** -NP_SPIN_PARAL: 1 -NP_KPOINT_PARAL: 1 -NP_BAND_PARAL: 16 -NP_DOMAIN_PARAL: 2 3 1 -NP_DOMAIN_PHI_PARAL: 6 4 4 -EIG_SERIAL_MAXNS: 1500 -*************************************************************************** - Initialization -*************************************************************************** -Number of processors : 96 -Mesh spacing in x-direction : 0.299891 (Bohr) -Mesh spacing in y-direction : 0.299891 (Bohr) -Mesh spacing in z-direction : 0.297851 (Bohr) -Number of symmetry adapted k-points: 1 -Output printed to : Al18Si18_NPTNP/temp_run/Al18Si18_NPTNP.out -MD output printed to : Al18Si18_NPTNP/temp_run/Al18Si18_NPTNP.aimd -Total number of atom types : 2 -Total number of atoms : 36 -Total number of electrons : 126 -Atom type 1 (valence electrons) : Si 4 -Pseudopotential : ../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 -Atomic mass : 28.0855 -Pseudocharge radii of atom type 1 : 9.00 9.00 8.94 (x, y, z dir) -Number of atoms of type 1 : 18 -Atom type 2 (valence electrons) : Al 3 -Pseudopotential : ../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 -Atomic mass : 26.9815385 -Pseudocharge radii of atom type 2 : 8.70 8.70 8.94 (x, y, z dir) -Number of atoms of type 2 : 18 -Estimated total memory usage : 1.17 GB -Estimated memory per processor : 12.52 MB -WARNING: Atoms are too close to boundary for b calculation. -=================================================================== - Self Consistent Field (SCF#1) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2218586983E+00 7.146E-02 2.203 -2 -3.2411300735E+00 3.430E-02 0.670 -3 -3.2448644362E+00 3.946E-02 0.649 -4 -3.2459869009E+00 3.031E-02 0.698 -5 -3.2465961931E+00 1.294E-02 0.723 -6 -3.2467122531E+00 2.068E-02 0.667 -7 -3.2468458114E+00 7.018E-03 0.689 -8 -3.2468526665E+00 7.323E-03 0.638 -9 -3.2468713044E+00 1.320E-03 0.635 -10 -3.2468728085E+00 6.838E-04 0.740 -11 -3.2468729941E+00 1.011E-03 0.622 -12 -3.2468733809E+00 1.405E-04 0.624 -13 -3.2468734125E+00 6.576E-05 0.641 -14 -3.2468734211E+00 3.822E-05 0.741 -15 -3.2468734238E+00 2.150E-05 0.474 -16 -3.2468734246E+00 8.566E-06 0.575 -17 -3.2468734249E+00 3.560E-06 0.605 -18 -3.2468734251E+00 2.057E-06 0.582 -19 -3.2468734252E+00 7.085E-07 0.488 -20 -3.2468734241E+00 4.722E-07 0.560 -Total number of SCF: 20 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468734241E+00 (Ha/atom) -Total free energy : -1.1688744327E+02 (Ha) -Band structure energy : -4.0126458888E+00 (Ha) -Exchange correlation energy : -4.7115258674E+01 (Ha) -Self and correction energy : -1.8563761237E+02 (Ha) --Entropy*kb*T : -3.2492185469E-02 (Ha) -Fermi level : 1.2923881918E-01 (Ha) -RMS force : 1.7434732139E-02 (Ha/Bohr) -Maximum force : 1.9658385389E-02 (Ha/Bohr) -Time for force calculation : 0.074 (sec) -Pressure : 1.3263939851E+01 (GPa) -Maximum stress : 1.5695363190E+01 (GPa) -Time for stress calculation : 0.167 (sec) -MD step time : 19.464 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9603676873934 30.9603676873934 20.640245124929 -CHEB_DEGREE: 31 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299894 (Bohr) -Mesh spacing in y-direction : 0.299894 (Bohr) -Mesh spacing in z direction : 0.297854 (Bohr) -=================================================================== - Self Consistent Field (SCF#2) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2465435114E+00 3.302E-02 0.668 -2 -3.2468325683E+00 9.750E-03 0.647 -3 -3.2468586161E+00 4.837E-03 0.530 -4 -3.2468676110E+00 1.225E-03 0.657 -5 -3.2468683673E+00 3.786E-04 0.512 -6 -3.2468684607E+00 2.312E-04 0.680 -7 -3.2468684820E+00 9.284E-05 0.597 -8 -3.2468684871E+00 3.850E-05 0.622 -9 -3.2468684877E+00 1.557E-05 0.599 -10 -3.2468684878E+00 8.205E-06 0.473 -11 -3.2468684878E+00 3.202E-06 0.573 -12 -3.2468684879E+00 1.358E-06 0.587 -13 -3.2468684878E+00 8.717E-07 0.582 -14 -3.2468684878E+00 3.338E-07 0.558 -Total number of SCF: 14 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468684878E+00 (Ha/atom) -Total free energy : -1.1688726556E+02 (Ha) -Band structure energy : -4.0134593500E+00 (Ha) -Exchange correlation energy : -4.7115097047E+01 (Ha) -Self and correction energy : -1.8563761176E+02 (Ha) --Entropy*kb*T : -3.2464536729E-02 (Ha) -Fermi level : 1.2923111743E-01 (Ha) -RMS force : 1.7495111495E-02 (Ha/Bohr) -Maximum force : 2.1522465800E-02 (Ha/Bohr) -Time for force calculation : 0.073 (sec) -Pressure : 1.3263381546E+01 (GPa) -Maximum stress : 1.5696517346E+01 (GPa) -Time for stress calculation : 0.161 (sec) -MD step time : 12.330 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9611027296076 30.9611027296076 20.6407351530717 -CHEB_DEGREE: 31 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299901 (Bohr) -Mesh spacing in y-direction : 0.299901 (Bohr) -Mesh spacing in z direction : 0.297861 (Bohr) -=================================================================== - Self Consistent Field (SCF#3) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2465370698E+00 3.300E-02 0.666 -2 -3.2468257104E+00 9.783E-03 0.650 -3 -3.2468519105E+00 4.819E-03 0.660 -4 -3.2468608367E+00 1.230E-03 0.668 -5 -3.2468615960E+00 3.791E-04 0.655 -6 -3.2468616894E+00 2.305E-04 0.609 -7 -3.2468617107E+00 9.183E-05 0.490 -8 -3.2468617157E+00 3.837E-05 0.652 -9 -3.2468617163E+00 1.545E-05 0.628 -10 -3.2468617164E+00 8.138E-06 0.593 -11 -3.2468617164E+00 3.244E-06 0.594 -12 -3.2468617165E+00 1.371E-06 0.588 -13 -3.2468617164E+00 8.708E-07 0.573 -14 -3.2468617164E+00 3.409E-07 0.586 -Total number of SCF: 14 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468617164E+00 (Ha/atom) -Total free energy : -1.1688702179E+02 (Ha) -Band structure energy : -4.0151140171E+00 (Ha) -Exchange correlation energy : -4.7114660874E+01 (Ha) -Self and correction energy : -1.8563761120E+02 (Ha) --Entropy*kb*T : -3.2442420793E-02 (Ha) -Fermi level : 1.2921587693E-01 (Ha) -RMS force : 1.7565982483E-02 (Ha/Bohr) -Maximum force : 2.3941865343E-02 (Ha/Bohr) -Time for force calculation : 0.072 (sec) -Pressure : 1.3260433595E+01 (GPa) -Maximum stress : 1.5693526044E+01 (GPa) -Time for stress calculation : 0.159 (sec) -MD step time : 10.110 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9622034474202 30.9622034474202 20.6414689649468 -CHEB_DEGREE: 31 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299912 (Bohr) -Mesh spacing in y-direction : 0.299912 (Bohr) -Mesh spacing in z direction : 0.297872 (Bohr) -=================================================================== - Self Consistent Field (SCF#4) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2468526224E+00 2.644E-03 0.647 -2 -3.2468530625E+00 1.868E-03 0.607 -3 -3.2468530899E+00 3.463E-04 0.673 -4 -3.2468531068E+00 6.241E-05 0.637 -5 -3.2468531082E+00 3.239E-05 0.586 -6 -3.2468531087E+00 1.716E-05 0.598 -7 -3.2468531089E+00 4.179E-06 0.593 -8 -3.2468531089E+00 2.557E-06 0.571 -9 -3.2468531089E+00 9.617E-07 4.769 -10 -3.2468531086E+00 4.231E-07 0.438 -Total number of SCF: 10 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468531086E+00 (Ha/atom) -Total free energy : -1.1688671191E+02 (Ha) -Band structure energy : -4.0176087414E+00 (Ha) -Exchange correlation energy : -4.7113952860E+01 (Ha) -Self and correction energy : -1.8563761073E+02 (Ha) --Entropy*kb*T : -3.2426003230E-02 (Ha) -Fermi level : 1.2919307712E-01 (Ha) -RMS force : 1.7648356115E-02 (Ha/Bohr) -Maximum force : 2.6406962025E-02 (Ha/Bohr) -Time for force calculation : 0.074 (sec) -Pressure : 1.3255135630E+01 (GPa) -Maximum stress : 1.5686455687E+01 (GPa) -Time for stress calculation : 0.160 (sec) -MD step time : 13.963 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9636663218099 30.9636663218099 20.64244421454 -CHEB_DEGREE: 31 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299926 (Bohr) -Mesh spacing in y-direction : 0.299926 (Bohr) -Mesh spacing in z direction : 0.297886 (Bohr) -=================================================================== - Self Consistent Field (SCF#5) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2468421208E+00 4.628E-03 0.670 -2 -3.2468425906E+00 3.293E-03 0.641 -3 -3.2468426512E+00 3.176E-04 0.540 -4 -3.2468426777E+00 1.071E-04 0.623 -5 -3.2468426801E+00 3.716E-05 0.480 -6 -3.2468426807E+00 2.311E-05 0.597 -7 -3.2468426816E+00 5.220E-06 0.578 -8 -3.2468426812E+00 2.807E-06 0.571 -9 -3.2468426817E+00 1.481E-06 0.547 -10 -3.2468426797E+00 7.597E-07 0.540 -11 -3.2468426804E+00 2.707E-07 0.442 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468426804E+00 (Ha/atom) -Total free energy : -1.1688633650E+02 (Ha) -Band structure energy : -4.0209302848E+00 (Ha) -Exchange correlation energy : -4.7112973958E+01 (Ha) -Self and correction energy : -1.8563761036E+02 (Ha) --Entropy*kb*T : -3.2415347977E-02 (Ha) -Fermi level : 1.2916283553E-01 (Ha) -RMS force : 1.7744263701E-02 (Ha/Bohr) -Maximum force : 2.8911718087E-02 (Ha/Bohr) -Time for force calculation : 0.072 (sec) -Pressure : 1.3247490179E+01 (GPa) -Maximum stress : 1.5675330760E+01 (GPa) -Time for stress calculation : 0.160 (sec) -MD step time : 10.028 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9654857341844 30.9654857341844 20.6436571561229 -CHEB_DEGREE: 31 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299944 (Bohr) -Mesh spacing in y-direction : 0.299944 (Bohr) -Mesh spacing in z direction : 0.297903 (Bohr) -=================================================================== - Self Consistent Field (SCF#6) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2468298675E+00 4.615E-03 0.657 -2 -3.2468303813E+00 3.271E-03 0.636 -3 -3.2468304433E+00 3.581E-04 0.497 -4 -3.2468304677E+00 7.726E-05 0.586 -5 -3.2468304689E+00 3.590E-05 0.575 -6 -3.2468304698E+00 2.330E-05 0.470 -7 -3.2468304702E+00 4.543E-06 0.557 -8 -3.2468304701E+00 2.842E-06 0.554 -9 -3.2468304703E+00 9.461E-07 0.448 -10 -3.2468304686E+00 6.014E-07 0.538 -11 -3.2468304694E+00 2.802E-07 0.432 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468304694E+00 (Ha/atom) -Total free energy : -1.1688589690E+02 (Ha) -Band structure energy : -4.0250731170E+00 (Ha) -Exchange correlation energy : -4.7111729199E+01 (Ha) -Self and correction energy : -1.8563761007E+02 (Ha) --Entropy*kb*T : -3.2410364797E-02 (Ha) -Fermi level : 1.2912519430E-01 (Ha) -RMS force : 1.7856272288E-02 (Ha/Bohr) -Maximum force : 3.1450061744E-02 (Ha/Bohr) -Time for force calculation : 0.072 (sec) -Pressure : 1.3237541251E+01 (GPa) -Maximum stress : 1.5660213675E+01 (GPa) -Time for stress calculation : 0.160 (sec) -MD step time : 11.398 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9676541309443 30.9676541309443 20.6451027539629 -CHEB_DEGREE: 31 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299965 (Bohr) -Mesh spacing in y-direction : 0.299965 (Bohr) -Mesh spacing in z direction : 0.297924 (Bohr) -=================================================================== - Self Consistent Field (SCF#7) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2468159710E+00 4.540E-03 0.631 -2 -3.2468164280E+00 3.234E-03 0.624 -3 -3.2468164901E+00 3.100E-04 0.661 -4 -3.2468165163E+00 1.038E-04 0.600 -5 -3.2468165186E+00 3.773E-05 0.587 -6 -3.2468165190E+00 2.477E-05 0.587 -7 -3.2468165202E+00 5.297E-06 0.621 -8 -3.2468165195E+00 3.049E-06 0.534 -9 -3.2468165203E+00 1.297E-06 0.638 -10 -3.2468165193E+00 7.660E-07 0.443 -11 -3.2468165190E+00 2.577E-07 0.539 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468165190E+00 (Ha/atom) -Total free energy : -1.1688539468E+02 (Ha) -Band structure energy : -4.0300114459E+00 (Ha) -Exchange correlation energy : -4.7110223768E+01 (Ha) -Self and correction energy : -1.8563760992E+02 (Ha) --Entropy*kb*T : -3.2410946614E-02 (Ha) -Fermi level : 1.2908038516E-01 (Ha) -RMS force : 1.7987790731E-02 (Ha/Bohr) -Maximum force : 3.4015897996E-02 (Ha/Bohr) -Time for force calculation : 0.071 (sec) -Pressure : 1.3225325673E+01 (GPa) -Maximum stress : 1.5641152892E+01 (GPa) -Time for stress calculation : 0.160 (sec) -MD step time : 10.397 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9701625759677 30.9701625759677 20.6467750506451 -CHEB_DEGREE: 31 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.299989 (Bohr) -Mesh spacing in y-direction : 0.299989 (Bohr) -Mesh spacing in z direction : 0.297948 (Bohr) -=================================================================== - Self Consistent Field (SCF#8) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2468002463E+00 4.484E-03 0.696 -2 -3.2468007759E+00 3.170E-03 0.615 -3 -3.2468008394E+00 3.687E-04 0.632 -4 -3.2468008604E+00 6.472E-05 0.582 -5 -3.2468008617E+00 3.873E-05 0.774 -6 -3.2468008620E+00 9.059E-06 0.476 -7 -3.2468008620E+00 4.735E-06 0.596 -8 -3.2468008628E+00 3.508E-06 0.539 -9 -3.2468008627E+00 1.725E-06 0.585 -10 -3.2468008626E+00 6.396E-07 0.562 -11 -3.2468008620E+00 2.897E-07 0.541 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468008620E+00 (Ha/atom) -Total free energy : -1.1688483103E+02 (Ha) -Band structure energy : -4.0357334972E+00 (Ha) -Exchange correlation energy : -4.7108464659E+01 (Ha) -Self and correction energy : -1.8563760992E+02 (Ha) --Entropy*kb*T : -3.2416927520E-02 (Ha) -Fermi level : 1.2902854393E-01 (Ha) -RMS force : 1.8142361261E-02 (Ha/Bohr) -Maximum force : 3.6603628263E-02 (Ha/Bohr) -Time for force calculation : 0.073 (sec) -Pressure : 1.3210907961E+01 (GPa) -Maximum stress : 1.5618228245E+01 (GPa) -Time for stress calculation : 0.159 (sec) -MD step time : 9.220 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9730014882755 30.9730014882755 20.6486676588503 -CHEB_DEGREE: 31 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.300017 (Bohr) -Mesh spacing in y-direction : 0.300017 (Bohr) -Mesh spacing in z direction : 0.297976 (Bohr) -=================================================================== - Self Consistent Field (SCF#9) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2467829657E+00 4.550E-03 0.607 -2 -3.2467834488E+00 3.235E-03 0.607 -3 -3.2467835159E+00 3.012E-04 0.650 -4 -3.2467835394E+00 7.951E-05 0.487 -5 -3.2467835407E+00 3.809E-05 0.570 -6 -3.2467835417E+00 2.084E-05 0.572 -7 -3.2467835420E+00 4.901E-06 0.584 -8 -3.2467835422E+00 3.533E-06 0.558 -9 -3.2467835413E+00 9.900E-07 0.562 -10 -3.2467835405E+00 6.929E-07 0.497 -11 -3.2467835415E+00 3.172E-07 0.537 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2467835415E+00 (Ha/atom) -Total free energy : -1.1688420749E+02 (Ha) -Band structure energy : -4.0422129424E+00 (Ha) -Exchange correlation energy : -4.7106459194E+01 (Ha) -Self and correction energy : -1.8563761008E+02 (Ha) --Entropy*kb*T : -3.2428085123E-02 (Ha) -Fermi level : 1.2896992426E-01 (Ha) -RMS force : 1.8323003115E-02 (Ha/Bohr) -Maximum force : 3.9206412895E-02 (Ha/Bohr) -Time for force calculation : 0.073 (sec) -Pressure : 1.3194352431E+01 (GPa) -Maximum stress : 1.5591526392E+01 (GPa) -Time for stress calculation : 0.163 (sec) -MD step time : 9.189 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9761612460032 30.9761612460032 20.6507741640022 -CHEB_DEGREE: 31 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing in x-direction : 0.300047 (Bohr) -Mesh spacing in y-direction : 0.300047 (Bohr) -Mesh spacing in z direction : 0.298006 (Bohr) -=================================================================== - Self Consistent Field (SCF#10) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2467640200E+00 4.611E-03 0.615 -2 -3.2467645265E+00 3.272E-03 0.497 -3 -3.2467645937E+00 3.326E-04 0.603 -4 -3.2467646167E+00 7.571E-05 0.591 -5 -3.2467646179E+00 3.797E-05 0.572 -6 -3.2467646188E+00 2.147E-05 0.597 -7 -3.2467646191E+00 4.497E-06 0.606 -8 -3.2467646192E+00 2.751E-06 0.571 -9 -3.2467646192E+00 9.176E-07 0.551 -10 -3.2467646178E+00 5.701E-07 0.568 -11 -3.2467646188E+00 2.929E-07 0.534 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2467646188E+00 (Ha/atom) -Total free energy : -1.1688352628E+02 (Ha) -Band structure energy : -4.0494240072E+00 (Ha) -Exchange correlation energy : -4.7104213784E+01 (Ha) -Self and correction energy : -1.8563761044E+02 (Ha) --Entropy*kb*T : -3.2444119367E-02 (Ha) -Fermi level : 1.2890478106E-01 (Ha) -RMS force : 1.8531616125E-02 (Ha/Bohr) -Maximum force : 4.1815096511E-02 (Ha/Bohr) -Time for force calculation : 0.071 (sec) -Pressure : 1.3175705209E+01 (GPa) -Maximum stress : 1.5561112203E+01 (GPa) -Time for stress calculation : 0.159 (sec) -MD step time : 7.624 (sec) -*************************************************************************** - Timing info -*************************************************************************** -Total walltime : 113.922 sec -___________________________________________________________________________ - -*************************************************************************** -* Material Physics & Mechanics Group, Georgia Tech * -* PI: Phanish Suryanarayana * -* List of contributors: See the documentation * -* Citation: See README.md or the documentation for details * -* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * -* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * -*************************************************************************** - diff --git a/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.inpt b/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.inpt deleted file mode 100644 index 869a8550..00000000 --- a/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.inpt +++ /dev/null @@ -1,38 +0,0 @@ -# nprocs: 24 - -# Test: Si18Al18 -LATVEC: -0.5 0.5 0.0 -0.0 0.5 0.5 -0.5 0.0 0.5 -LATVEC_SCALE: 30.96 30.96 20.64 # 3 3 2 Si8(2) cell -MESH_SPACING: 0.35 -FD_ORDER: 12 -BC: P P P -KPOINT_GRID: 1 1 1 -EXCHANGE_CORRELATION: GGA_PBE -ELEC_TEMP_TYPE: fermi-dirac -ELEC_TEMP: 1000 -TOL_SCF: 5e-7 -CALC_STRESS: 1 -PRINT_FORCES: 1 -PRINT_ATOMS: 1 -MIXING_VARIABLE: potential -MIXING_PRECOND: kerker -# NSTATES: 135 - -# MD -MD_FLAG: 1 # 1 = MD, 0 = no MD (default) -ION_TEMP: 1000 # kelvin -# ION_TEMP_END: 1120 -MD_METHOD: NPT_NP # NVE, NVT_NH (Nose-Hoover), NVK_G (Gaussian) -#QMASS: 1600 # mass for NH thermostat -MD_TIMESTEP: 0.4 # fs 0.6 -MD_NSTEP: 10 # run MD for MD_NSTEP steps or TWTIME minutes, whichever comes first -#TWTIME: 1400 -RESTART_FLAG: 0 # 1 = restart MD from .restart file if present, 0 = start new -# ION_VEL_DSTR: 1 # Initial velocities: 1 = uniform, 2 = Maxwell-Boltzmann (default) -TARGET_PRESSURE: 12 GPa -NPT_NP_QMASS: 500.0 -NPT_NP_BMASS: 0.05 -#NPT_SCALE_CONSTRAINTS: 123 diff --git a/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.ion b/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.ion deleted file mode 100644 index dc7c22bc..00000000 --- a/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.ion +++ /dev/null @@ -1,63 +0,0 @@ -#========================= -# format of ion file -#========================= -# ATOM_TYPE: -# N_TYPE_ATOM: -# COORD: -# -# ... -# RELAX: -# -# ... - - -# Reminder: when changing number of atoms, change the RELAX flags accordingly -# as well. - -ATOM_TYPE: Si # atom type followed with valence charge -N_TYPE_ATOM: 18 # number of atoms of this type -PSEUDO_POT: ../../../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 -ATOMIC_MASS: 28.0855 -COORD_FRAC: # coordinates follows -0.003 0.004 0.006 -0.3363 0.004 0.006 -0.6697 0.004 0.006 -0.003 0.337 0.006 -0.3363 0.337 0.006 -0.6697 0.337 0.006 -0.003 0.671 0.006 -0.3363 0.671 0.006 -0.6697 0.671 0.006 -0.003 0.004 0.501 -0.3363 0.004 0.501 -0.6697 0.004 0.501 -0.003 0.337 0.501 -0.3363 0.337 0.501 -0.6697 0.337 0.501 -0.003 0.671 0.501 -0.3363 0.671 0.501 -0.6697 0.671 0.501 - -ATOM_TYPE: Al # atom type followed with valence charge -N_TYPE_ATOM: 18 # number of atoms of this type -PSEUDO_POT: ../../../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 -ATOMIC_MASS: 26.9815385 -COORD_FRAC: # coordinates follows -0.083333333 0.083333333 0.125 -0.416633333 0.083333333 0.125 -0.750033333 0.083333333 0.125 -0.083333333 0.416333333 0.125 -0.416633333 0.416333333 0.125 -0.750033333 0.416333333 0.125 -0.083333333 0.750333333 0.125 -0.416633333 0.750333333 0.125 -0.750033333 0.750333333 0.125 -0.083333333 0.083333333 0.62 -0.416633333 0.083333333 0.62 -0.750033333 0.083333333 0.62 -0.083333333 0.416333333 0.62 -0.416633333 0.416333333 0.62 -0.750033333 0.416333333 0.62 -0.083333333 0.750333333 0.62 -0.416633333 0.750333333 0.62 -0.750033333 0.750333333 0.62 diff --git a/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.refaimd b/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.refaimd deleted file mode 100644 index 0f8c8aa7..00000000 --- a/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.refaimd +++ /dev/null @@ -1,1419 +0,0 @@ -:Description: - -:Desc_R: Atom positions in Cartesian coordinates. Unit=Bohr -:Desc_V: Atomic velocities in Cartesian coordinates. Unit=Bohr/atu - where atu is the atomic unit of time, hbar/Ha -:Desc_F: Atomic forces in Cartesian coordinates. Unit=Ha/Bohr -:Desc_MDTM: MD time. Unit=second -:Desc_TEL: Electronic temperature. Unit=Kelvin -:Desc_TIO: Ionic temperature. Unit=Kelvin -:Desc_TEN: Total energy. TEN = KEN + FEN. Unit=Ha/atom -:Desc_KEN: Ionic kinetic energy. Unit=Ha/atom -:Desc_KENIG: Kinetic energy: 3/2 N k T of ideal gas at temperature T = TIO. Unit=Ha/atom - where N = number of particles, k = Boltzmann constant -:Desc_FEN: Free energy F = U - TS. FEN = UEN + TSEN. Unit=Ha/atom -:Desc_UEN: Internal energy. Unit=Ha/atom -:Desc_TSEN: Electronic entropic contribution -TS to free energy F = U - TS. Unit=Ha/atom -:Desc_LATVEC_SCALE: ratio of cell lattice vectors over input lattice vector. Unit = 1 -:Desc_NPT_NP_HAMIL: Hamiltonian of the NPT_NP system, formula (10) in (E. Hernandez, 2001). Unit = Ha/atom -:Desc_STRESS: Stress, excluding ion-kinetic contribution. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_STRIO: Ion-kinetic stress in cartesian coordinate. Unit=GPa(all periodic),Ha/Bohr**2(surface),Ha/Bohr(wire) -:Desc_PRESIO: Ion-kinetic pressure in cartesian coordinate. Unit=GPa -:Desc_PRES: Pressure, excluding ion-kinetic contribution. Unit=GPa -:Desc_PRESIG: Pressure N k T/V of ideal gas at temperature T = TIO. Unit=GPa - where N = number of particles, k = Boltzmann constant, V = volume -:Desc_AVGV: Average of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MAXV: Maximum of the speed of all ions of the same type. Unit=Bohr/atu -:Desc_MIND: Minimum of the distance of all ions of the same type. Unit=Bohr - - -:MDSTEP: 1 -:MDTM: 17.72 -:TWIST: 0 -:TEL: 1000 -:TIO: 1000 -:TEN: -3.2422691228E+00 -:KEN: 4.6182668634E-03 -:KENIG: 4.7502173452E-03 -:FEN: -3.2468873896E+00 -:UEN: -3.2459852691E+00 -:TSEN: -9.0212050948E-04 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 1.0836000000E-01 1.0836000000E-01 1.2384000000E-01 - 5.2678440000E+00 5.2678440000E+00 1.2384000000E-01 - 1.0428876000E+01 1.0428876000E+01 1.2384000000E-01 - 1.0836000000E-01 5.2632000000E+00 5.2786800000E+00 - 5.2678440000E+00 1.0422684000E+01 5.2786800000E+00 - 1.0428876000E+01 1.5583716000E+01 5.2786800000E+00 - 1.0836000000E-01 1.0433520000E+01 1.0449000000E+01 - 5.2678440000E+00 1.5593004000E+01 1.0449000000E+01 - 1.0428876000E+01 2.0754036000E+01 1.0449000000E+01 - 5.2167600000E+00 1.0836000000E-01 5.2322400000E+00 - 1.0376244000E+01 5.2678440000E+00 5.2322400000E+00 - 1.5537276000E+01 1.0428876000E+01 5.2322400000E+00 - 5.2167600000E+00 5.2632000000E+00 1.0387080000E+01 - 1.0376244000E+01 1.0422684000E+01 1.0387080000E+01 - 1.5537276000E+01 1.5583716000E+01 1.0387080000E+01 - 5.2167600000E+00 1.0433520000E+01 1.5557400000E+01 - 1.0376244000E+01 1.5593004000E+01 1.5557400000E+01 - 1.5537276000E+01 2.0754036000E+01 1.5557400000E+01 - 2.5799999948E+00 2.5799999897E+00 2.5799999948E+00 - 7.7394839948E+00 7.7394839897E+00 2.5799999948E+00 - 1.2900515995E+01 1.2900515990E+01 2.5799999948E+00 - 2.5799999948E+00 7.7348399897E+00 7.7348399948E+00 - 7.7394839948E+00 1.2894323990E+01 7.7348399948E+00 - 1.2900515995E+01 1.8055355990E+01 7.7348399948E+00 - 2.5799999948E+00 1.2905159990E+01 1.2905159995E+01 - 7.7394839948E+00 1.8064643990E+01 1.2905159995E+01 - 1.2900515995E+01 2.3225675990E+01 1.2905159995E+01 - 7.6883999948E+00 2.5799999897E+00 7.6883999948E+00 - 1.2847883995E+01 7.7394839897E+00 7.6883999948E+00 - 1.8008915995E+01 1.2900515990E+01 7.6883999948E+00 - 7.6883999948E+00 7.7348399897E+00 1.2843239995E+01 - 1.2847883995E+01 1.2894323990E+01 1.2843239995E+01 - 1.8008915995E+01 1.8055355990E+01 1.2843239995E+01 - 7.6883999948E+00 1.2905159990E+01 1.8013559995E+01 - 1.2847883995E+01 1.8064643990E+01 1.8013559995E+01 - 1.8008915995E+01 2.3225675990E+01 1.8013559995E+01 -:V: - -6.0245009366E-07 5.0610838342E-04 3.0608266695E-04 - 2.9938984517E-05 -7.8901597789E-05 3.6016903910E-04 - 4.4972762428E-04 -2.8444441337E-04 -2.1122595649E-04 - -2.2481092799E-04 -6.4308057382E-05 -3.0900434353E-04 - 2.0159013658E-04 3.1059192089E-04 -2.1544169161E-05 - -1.1635182314E-04 2.8600741191E-04 -3.9508449999E-05 - -5.4680597612E-04 -3.8068816092E-04 1.8606202609E-04 - 3.2800903095E-05 1.2068768104E-04 2.7417358068E-04 - 3.1797054100E-04 -2.9842962794E-04 1.0359838584E-04 - -3.0676290696E-04 1.1167632141E-05 -4.2615937266E-04 - 1.6878744722E-05 4.3374116342E-05 -2.1120686257E-04 - 7.0760181861E-05 -2.9900063254E-04 3.0300451979E-04 - 3.8368497007E-04 -2.4059320899E-06 2.6540479441E-04 - 5.4747359958E-04 2.7168591071E-04 -3.3368346166E-05 - -4.7929758031E-04 4.2557459113E-04 -2.0470058895E-04 - 4.5340025918E-05 -5.5027479884E-04 -3.9120591677E-05 - -2.1924503718E-04 4.4304085342E-04 -1.7492054567E-05 - -9.5118584190E-05 3.6704244143E-05 -2.9582607050E-04 - 1.2197128562E-04 1.1395578019E-04 1.4006655013E-04 - -1.4267212210E-04 8.0783386218E-06 -5.7486714718E-05 - 1.9411669186E-04 -3.0664672216E-04 -5.0071124004E-04 - -1.3008652719E-04 -9.5604641977E-05 -2.0021704404E-04 - -5.9220663824E-05 -1.4618834423E-04 1.6024106415E-04 - -2.6504261105E-04 5.0003042978E-05 -1.0868544585E-04 - 1.6420255400E-04 2.2604163647E-04 1.4620774400E-04 - -5.1205374341E-04 -6.5216683506E-05 1.7672092139E-05 - 1.9123267548E-04 -2.2013241880E-04 -3.3512644184E-04 - 1.8242179630E-05 -2.2469638365E-04 3.1701805888E-04 - 2.7575448470E-04 -1.3396672528E-04 6.7237077754E-05 - -1.9035475988E-04 1.5510168323E-04 1.9749233591E-04 - -7.0764929449E-05 -2.2635554084E-05 9.6448428348E-05 - -8.9992731496E-05 -3.9118784261E-04 -5.1654558178E-04 - 1.3741131460E-04 2.9394207988E-04 3.6994077957E-04 - 2.2240738324E-04 -7.3145707163E-06 1.0717984225E-04 - 1.5069227647E-04 2.4275500768E-04 4.4585407812E-05 - -1.2739810789E-04 6.9087067276E-06 6.5781112690E-05 -:F: - -1.1921299607E-02 -8.3098203650E-03 -1.2321697009E-02 - -1.1917987456E-02 -8.3035987763E-03 -1.2335230915E-02 - -1.2016992029E-02 -8.3961651407E-03 -1.2247763960E-02 - -1.2052700380E-02 -8.2487927788E-03 -1.2290113303E-02 - -1.2049684192E-02 -8.2427516130E-03 -1.2303624446E-02 - -1.2148354660E-02 -8.3354156409E-03 -1.2216048342E-02 - -1.1204943502E-02 -9.1321596896E-03 -1.3239466414E-02 - -1.1201934353E-02 -9.1262549904E-03 -1.3253058464E-02 - -1.1300386094E-02 -9.2184909340E-03 -1.3165057447E-02 - -5.2069840996E-03 -1.3354408960E-02 -5.5569114354E-03 - -5.2037036001E-03 -1.3349174244E-02 -5.5712551319E-03 - -5.3028703874E-03 -1.3440215760E-02 -5.4824553929E-03 - -5.3438437670E-03 -1.3300185074E-02 -5.5219141476E-03 - -5.3400532135E-03 -1.3294491822E-02 -5.5357949377E-03 - -5.4392791991E-03 -1.3385797607E-02 -5.4470422054E-03 - -4.4856459243E-03 -1.4168366834E-02 -6.4754241128E-03 - -4.4823406885E-03 -1.4163142435E-02 -6.4892629580E-03 - -4.5817094146E-03 -1.4254089069E-02 -6.4008728286E-03 - 5.7059549250E-03 1.3234408417E-02 6.0507865919E-03 - 5.7955403413E-03 1.3317019728E-02 5.9773024923E-03 - 5.7080349219E-03 1.3235530656E-02 6.0568694922E-03 - 5.0002947303E-03 1.4020078281E-02 6.9091424554E-03 - 5.0900145458E-03 1.4102686968E-02 6.8357378950E-03 - 5.0024854411E-03 1.4021121241E-02 6.9152447442E-03 - 5.7645081761E-03 1.3240713304E-02 6.0691265595E-03 - 5.8542417860E-03 1.3323475098E-02 5.9956185910E-03 - 5.7665217432E-03 1.3241581801E-02 6.0751879898E-03 - 1.1462995112E-02 8.4080105037E-03 1.1838341016E-02 - 1.1552766205E-02 8.4913707890E-03 1.1765899096E-02 - 1.1465205730E-02 8.4082655320E-03 1.1843967180E-02 - 1.0767110745E-02 9.1986980030E-03 1.2695062432E-02 - 1.0856686505E-02 9.2816924094E-03 1.2622354758E-02 - 1.0769006029E-02 9.1987156440E-03 1.2700423723E-02 - 1.1516023315E-02 8.4055311778E-03 1.1856319461E-02 - 1.1605335221E-02 8.4886899873E-03 1.1783751633E-02 - 1.1517987093E-02 8.4057321952E-03 1.1861857339E-02 -:LATVEC_SCALE: 3.0960000000E+01 3.0960000000E+01 2.0640000000E+01 -:STRIO: - -6.8163081252E-01 4.4511004792E-02 -9.4040732941E-02 - 4.4511004792E-02 -6.7955659619E-01 -1.3243527596E-01 - -9.4040732941E-02 -1.3243527596E-01 -6.1677292168E-01 -:STRESS: - -1.5697144436E+01 -5.1705833147E+00 -3.8937094045E+00 - -5.1705833147E+00 -8.7293250244E+00 -4.6784556010E+00 - -3.8937094045E+00 -4.6784556010E+00 -1.5375904011E+01 -:PRESIO: 6.5932011013E-01 -:PRES: 1.3267457824E+01 -:PRESIG: 6.7815782756E-01 -:MIND: -Si - Si: 7.2243685620E+00 -Al - Al: 7.2243685620E+00 -Si - Al: 4.2720873613E+00 -:MDSTEP: 2 -:MDTM: 10.87 -:TWIST: 0 -:TEL: 1000 -:TIO: 998.901932416524 -:TEN: -3.2422691524E+00 -:KEN: 4.6131956942E-03 -:KENIG: 4.7450012855E-03 -:FEN: -3.2468823481E+00 -:UEN: -3.2459810140E+00 -:TSEN: -9.0133404087E-04 -:NPT_NP_HAMIL: 0.0000000000E+00 -:R: - 1.0828765085E-01 1.1668640358E-01 1.2883733931E-01 - 5.2683381770E+00 5.2665575895E+00 1.2973169177E-01 - 1.0436373145E+01 1.0424251504E+01 1.2028301665E-01 - 1.0457921994E-01 5.2621551599E+00 5.2735672225E+00 - 5.2711760636E+00 1.0427900348E+01 5.2783208708E+00 - 1.0427011204E+01 1.5588586764E+01 5.2780242638E+00 - 9.9258925498E-02 1.0427300048E+01 1.0452130624E+01 - 5.2683893292E+00 1.5595136762E+01 1.0453587650E+01 - 1.0434198109E+01 2.0749298803E+01 1.0450767323E+01 - 5.2117213857E+00 1.0847463748E-01 5.2252252451E+00 - 1.0376618901E+01 5.2685527088E+00 5.2287798319E+00 - 1.5538602872E+01 1.0423983845E+01 5.2372838048E+00 - 5.2231385710E+00 5.2631518518E+00 1.0391563199E+01 - 1.0385392605E+01 1.0427229977E+01 1.0386622322E+01 - 1.5529505854E+01 1.5590867806E+01 1.0383789480E+01 - 5.2175479546E+00 1.0424468698E+01 1.5556903753E+01 - 1.0372717982E+01 1.5600440603E+01 1.5557261350E+01 - 1.5535863591E+01 2.0754814005E+01 1.5552659020E+01 - 2.5820794814E+00 2.5819887822E+00 2.5823806395E+00 - 7.7372490248E+00 7.7397837950E+00 2.5791132984E+00 - 1.2903911469E+01 1.2895672207E+01 2.5717841497E+00 - 2.5779072852E+00 7.7334290462E+00 7.7316595424E+00 - 7.7386251364E+00 1.2892138450E+01 7.7376200195E+00 - 1.2896314442E+01 1.8056475872E+01 7.7331732317E+00 - 2.5827781842E+00 1.2909125343E+01 1.2907765263E+01 - 7.7311408981E+00 1.8063854718E+01 1.2905639264E+01 - 1.2903864101E+01 2.3222385890E+01 1.2899805488E+01 - 7.6888569625E+00 2.5763616665E+00 7.6937998974E+00 - 1.2852661381E+01 7.7374079693E+00 7.6896688739E+00 - 1.8006046323E+01 1.2903281287E+01 7.6918233353E+00 - 7.6873811855E+00 7.7346089271E+00 1.2845058498E+01 - 1.2846609160E+01 1.2888060096E+01 1.2834921029E+01 - 1.8011462710E+01 1.8060483072E+01 1.2849581262E+01 - 7.6922335314E+00 1.2905239454E+01 1.8015612874E+01 - 1.2850593523E+01 1.8068920756E+01 1.8014577348E+01 - 1.8007087729E+01 2.3226113575E+01 1.8014928295E+01 -:V: - -4.4532577675E-06 5.0344996820E-04 3.0211815475E-04 - 2.6090803291E-05 -8.1587818831E-05 3.5620291177E-04 - 4.4586885780E-04 -2.8717101053E-04 -2.1519295215E-04 - -2.2871560725E-04 -6.6975831408E-05 -3.1299000208E-04 - 1.9770816347E-04 3.0794520533E-04 -2.5519541393E-05 - -1.2028187261E-04 2.8332951137E-04 -4.3456449265E-05 - -5.5045322662E-04 -3.8365740163E-04 1.8179494224E-04 - 2.9184164726E-05 1.1774590066E-04 2.6990659705E-04 - 3.1433653499E-04 -3.0142256270E-04 9.9351134487E-05 - -3.0846048337E-04 6.8545063118E-06 -4.2797606652E-04 - 1.5198722621E-05 3.9064322842E-05 -2.1301723446E-04 - 6.9050873358E-05 -3.0335728335E-04 3.0124903887E-04 - 3.8197837495E-04 -6.7022344943E-06 2.6363465136E-04 - 5.4577657649E-04 2.6740541663E-04 -3.5158200146E-05 - -4.8107898525E-04 4.2127244683E-04 -2.0647050642E-04 - 4.3893398875E-05 -5.5487946089E-04 -4.1214254591E-05 - -2.2070408136E-04 4.3848850406E-04 -1.9589085341E-05 - -9.6603399914E-05 3.2101808251E-05 -2.9790873531E-04 - 1.2389603178E-04 1.1841143163E-04 1.4210816229E-04 - -1.4073074213E-04 1.2556370573E-05 -5.5479878792E-05 - 1.9604581434E-04 -3.0221212973E-04 -4.9870024036E-04 - -1.2841189352E-04 -9.0895502892E-05 -1.9790416722E-04 - -5.7512251674E-05 -1.4145400743E-04 1.6254763098E-04 - -2.6337411894E-04 5.4719953752E-05 -1.0636585226E-04 - 1.6614914005E-04 2.3050512036E-04 1.4825583565E-04 - -5.1011145191E-04 -6.0740216587E-05 1.9688917069E-05 - 1.9318131616E-04 -2.1569138251E-04 -3.3310084372E-04 - 2.2097345506E-05 -2.2188078568E-04 3.2101465575E-04 - 2.7965295889E-04 -1.3111847473E-04 7.1196586980E-05 - -1.8650948203E-04 1.5793672366E-04 2.0148473275E-04 - -6.7148279114E-05 -1.9543802769E-05 1.0072184164E-04 - -8.6346942803E-05 -3.8808696941E-04 -5.1232785693E-04 - 1.4103921206E-04 2.9704997176E-04 3.7422993426E-04 - 2.2629078438E-04 -4.4887273415E-06 1.1117178950E-04 - 1.5460205220E-04 2.4562155677E-04 4.8549765188E-05 - -1.2353187457E-04 9.7353425917E-06 6.9772812031E-05 -:F: - -1.2027827132E-02 -8.6464800919E-03 -1.2751926388E-02 - -1.2027283270E-02 -8.4441739637E-03 -1.2664933925E-02 - -1.2692474076E-02 -8.7059271232E-03 -1.2432218903E-02 - -1.1790665871E-02 -8.1464188657E-03 -1.1785163155E-02 - -1.2664715677E-02 -8.6015801030E-03 -1.2447494476E-02 - -1.2034822432E-02 -9.3456763140E-03 -1.2810451369E-02 - -9.4538652045E-03 -8.1216714650E-03 -1.2849110144E-02 - -1.1653250722E-02 -9.6634725024E-03 -1.4302433965E-02 - -1.2352451650E-02 -9.3866716630E-03 -1.3233349925E-02 - -4.2866723850E-03 -1.2995207026E-02 -4.5499332942E-03 - -5.3725984956E-03 -1.3250178605E-02 -5.0432354836E-03 - -5.3853777311E-03 -1.2980013703E-02 -5.7402830338E-03 - -6.2695714281E-03 -1.3374258776E-02 -6.3854547211E-03 - -6.9487085591E-03 -1.4667675693E-02 -6.3557696303E-03 - -4.4463362495E-03 -1.2763686727E-02 -4.5348804853E-03 - -4.1699221327E-03 -1.3271758526E-02 -5.9429302200E-03 - -3.8398692199E-03 -1.4303907939E-02 -6.7112012916E-03 - -4.3555282756E-03 -1.4015013350E-02 -5.6591356990E-03 - 5.6736878558E-03 1.3500886894E-02 5.9859580383E-03 - 6.1395916585E-03 1.3919184009E-02 6.1489644188E-03 - 5.8445147639E-03 1.3675140668E-02 7.0943132797E-03 - 5.5114721436E-03 1.3999491921E-02 7.1311757481E-03 - 5.3301638006E-03 1.4385694114E-02 7.2553237549E-03 - 5.2732669958E-03 1.4260671469E-02 6.7716903625E-03 - 4.8346812248E-03 1.2400618333E-02 5.6204869599E-03 - 6.6183959717E-03 1.4173421313E-02 6.2352226167E-03 - 5.2781186777E-03 1.3108717572E-02 6.5799739211E-03 - 1.1023749588E-02 8.1228237475E-03 1.0850125006E-02 - 1.1077881743E-02 8.0741086708E-03 1.1723580552E-02 - 1.1603341860E-02 8.3468793406E-03 1.2043108353E-02 - 1.1558485254E-02 9.9761159394E-03 1.2204512263E-02 - 1.1827988553E-02 1.0577064087E-02 1.4380179516E-02 - 1.0180239272E-02 8.3034904437E-03 1.1456531222E-02 - 1.0891400532E-02 7.9854922206E-03 1.1108455492E-02 - 1.1673170576E-02 8.0261108191E-03 1.1645402937E-02 - 1.1431790042E-02 7.8478608765E-03 1.1964901667E-02 -:LATVEC_SCALE: 3.0960368711E+01 3.0960368711E+01 2.0640245807E+01 -:STRIO: - -6.8169816093E-01 4.5494026188E-02 -9.4160871578E-02 - 4.5494026188E-02 -6.7735805207E-01 -1.3184820749E-01 - -9.4160871578E-02 -1.3184820749E-01 -6.1686298759E-01 -:STRESS: - -1.5698232144E+01 -5.1699879859E+00 -3.9283630413E+00 - -5.1699879859E+00 -8.7204962927E+00 -4.6863856334E+00 - -3.9283630413E+00 -4.6863856334E+00 -1.5381945143E+01 -:PRESIO: 6.5863973353E-01 -:PRES: 1.3266891193E+01 -:PRESIG: 6.7738896254E-01 -:MIND: -Si - Si: 7.2123694446E+00 -Al - Al: 7.2162313571E+00 -Si - Al: 4.2552835823E+00 -:MDSTEP: 3 -:MDTM: 10.78 -:TWIST: 0 -:TEL: 1000 -:TIO: 997.036283947596 -:TEN: -3.2422706466E+00 -:KEN: 4.6045796317E-03 -:KENIG: 4.7361390498E-03 -:FEN: -3.2468752263E+00 -:UEN: -3.2459745223E+00 -:TSEN: -9.0070393429E-04 -:NPT_NP_HAMIL: 2.0777045415E-06 -:R: - 1.0815231784E-01 1.2496983723E-01 1.3376918751E-01 - 5.2688308797E+00 5.2652884334E+00 1.3555856480E-01 - 1.0443928281E+01 1.0419703482E+01 1.1666026425E-01 - 1.0073586209E-01 5.2611291657E+00 5.2684530914E+00 - 5.2745039065E+00 1.0433195939E+01 5.2779579532E+00 - 1.0425205739E+01 1.5593594108E+01 5.2773627313E+00 - 9.0106521926E-02 1.0421159376E+01 1.0455317629E+01 - 5.2689351943E+00 1.5597403883E+01 1.0458224254E+01 - 1.0439579522E+01 2.0744757242E+01 1.0452588657E+01 - 5.2067207576E+00 1.0852116650E-01 5.2182467954E+00 - 1.0377088620E+01 5.2692534601E+00 5.2253541587E+00 - 1.5540086106E+01 1.0419145270E+01 5.2423603549E+00 - 5.2295471856E+00 5.2630948523E+00 1.0396136886E+01 - 1.0394629643E+01 1.0431822634E+01 1.0386254144E+01 - 1.5521894975E+01 1.5598138462E+01 1.0380597530E+01 - 5.2183758718E+00 1.0415468506E+01 1.5556560707E+01 - 1.0369294064E+01 1.5607988005E+01 1.5557271878E+01 - 1.5534612412E+01 2.0755764200E+01 1.5548071772E+01 - 2.5842216919E+00 2.5840838036E+00 2.5848258146E+00 - 7.7351397432E+00 7.7402531384E+00 2.5782912803E+00 - 1.2907493692E+01 1.2891056805E+01 2.5636365385E+00 - 2.5758754290E+00 7.7321876351E+00 7.7286100178E+00 - 7.7378877848E+00 1.2890185786E+01 7.7405330460E+00 - 1.2892294698E+01 1.8057890095E+01 7.7316357487E+00 - 2.5856145941E+00 1.2913314089E+01 1.2910555906E+01 - 7.7229247344E+00 1.8063358970E+01 1.2906306833E+01 - 1.2907395796E+01 2.3219444206E+01 1.2894639842E+01 - 7.6894667961E+00 2.5727983593E+00 7.6993528479E+00 - 1.2857654312E+01 7.7354684319E+00 7.6910946989E+00 - 1.8003454737E+01 1.2906247102E+01 7.6954058988E+00 - 7.6865178729E+00 7.7345252973E+00 1.2847098068E+01 - 1.2845552636E+01 1.2882006951E+01 1.2826832877E+01 - 1.8014280855E+01 1.8065872299E+01 1.2856140488E+01 - 7.6962199817E+00 1.2905516859E+01 1.8017942285E+01 - 1.2853521426E+01 1.8073458037E+01 1.8015873978E+01 - 1.8005536836E+01 2.3226871187E+01 1.8016577731E+01 -:V: - -8.3412963453E-06 5.0084025438E-04 2.9810826557E-04 - 2.2214110994E-05 -8.4346123413E-05 3.5224091127E-04 - 4.4193075114E-04 -2.9008907805E-04 -2.1928872862E-04 - -2.3260903176E-04 -6.9632582012E-05 -3.1691246932E-04 - 1.9368826892E-04 3.0527849967E-04 -2.9550886475E-05 - -1.2421453225E-04 2.8041337224E-04 -4.7611632199E-05 - -5.5370925391E-04 -3.8642197243E-04 1.7770964671E-04 - 2.5429460458E-05 1.1466651869E-04 2.6538393026E-04 - 3.1046019186E-04 -3.0456580324E-04 9.5111532806E-05 - -3.0995839519E-04 2.6580251438E-06 -4.2960275187E-04 - 1.3468296693E-05 3.4797235463E-05 -2.1472470016E-04 - 6.7336012992E-05 -3.0766230569E-04 2.9950442147E-04 - 3.8009225910E-04 -1.1026152144E-05 2.6166781094E-04 - 5.4373092322E-04 2.6276381886E-04 -3.7224723061E-05 - -4.8269161727E-04 4.1730233468E-04 -2.0801131910E-04 - 4.2562073772E-05 -5.5937073778E-04 -4.3149596392E-05 - -2.2202552874E-04 4.3402701464E-04 -2.1764760773E-05 - -9.8046080119E-05 2.7585042515E-05 -2.9984625604E-04 - 1.2584962391E-04 1.2299560812E-04 1.4417344350E-04 - -1.3871722760E-04 1.7242523354E-05 -5.3432033964E-05 - 1.9808324873E-04 -2.9772317506E-04 -4.9649653230E-04 - -1.2660513468E-04 -8.6220173786E-05 -1.9557805398E-04 - -5.5740544485E-05 -1.3666727378E-04 1.6504732415E-04 - -2.6169683599E-04 5.9536382025E-05 -1.0412717055E-04 - 1.6783599452E-04 2.3476022873E-04 1.5020044311E-04 - -5.0807198657E-04 -5.5995359923E-05 2.1793264542E-05 - 1.9502720201E-04 -2.1136129556E-04 -3.3100956502E-04 - 2.5813140868E-05 -2.1922991152E-04 3.2478137425E-04 - 2.8348115403E-04 -1.2845079182E-04 7.5165719137E-05 - -1.8267503886E-04 1.6080186295E-04 2.0560898336E-04 - -6.3285270275E-05 -1.6195596145E-05 1.0486352771E-04 - -8.2400310887E-05 -3.8467142396E-04 -5.0767861374E-04 - 1.4451480156E-04 2.9995139407E-04 3.7822007250E-04 - 2.3003674309E-04 -1.8045386413E-06 1.1494865097E-04 - 1.5858473251E-04 2.4841087722E-04 5.2484320807E-05 - -1.1973209880E-04 1.2378442556E-05 7.3822589123E-05 -:F: - -1.2126845001E-02 -8.9774990141E-03 -1.3158970951E-02 - -1.2118256117E-02 -8.5743813766E-03 -1.2982708459E-02 - -1.3356471744E-02 -9.0133476332E-03 -1.2604689617E-02 - -1.1513011967E-02 -8.0409196886E-03 -1.1264045631E-02 - -1.3264451314E-02 -8.9518152489E-03 -1.2585253195E-02 - -1.1916999572E-02 -1.0337343490E-02 -1.3376519950E-02 - -7.6944441467E-03 -7.1017453515E-03 -1.2490211578E-02 - -1.2100018525E-02 -1.0201381890E-02 -1.5346465931E-02 - -1.3389938921E-02 -9.5447861575E-03 -1.3278059190E-02 - -3.3575176342E-03 -1.2647283776E-02 -3.5316031593E-03 - -5.5307971505E-03 -1.3136615062E-02 -4.5134725165E-03 - -5.4533827378E-03 -1.2508408805E-02 -5.9917654944E-03 - -7.1851179959E-03 -1.3449962234E-02 -7.2389046747E-03 - -8.5907516807E-03 -1.6063086804E-02 -7.2246003122E-03 - -3.4582626372E-03 -1.2154435467E-02 -3.6208246387E-03 - -3.8658360502E-03 -1.2366628246E-02 -5.4087338798E-03 - -3.2081416734E-03 -1.4419082604E-02 -6.9093155240E-03 - -4.1271752987E-03 -1.3763026191E-02 -4.9041752540E-03 - 5.6243874047E-03 1.3762245848E-02 5.9117195818E-03 - 6.4761769870E-03 1.4509781976E-02 6.3142749777E-03 - 5.9897713975E-03 1.4103503672E-02 8.1086861239E-03 - 6.0049295041E-03 1.3972364470E-02 7.3428002744E-03 - 5.5660594087E-03 1.4654543862E-02 7.6697900174E-03 - 5.5379813822E-03 1.4487359629E-02 6.6100638216E-03 - 3.9170849700E-03 1.1560639863E-02 5.1907800548E-03 - 7.3822046892E-03 1.5019146096E-02 6.4811747561E-03 - 4.7663811550E-03 1.2947742150E-02 7.0898095924E-03 - 1.0569285914E-02 7.8381461988E-03 9.8509082299E-03 - 1.0587553673E-02 7.6499015181E-03 1.1674950828E-02 - 1.1727925759E-02 8.2786028984E-03 1.2222050590E-02 - 1.2336496088E-02 1.0740560181E-02 1.1707350861E-02 - 1.2851955326E-02 1.1891666832E-02 1.6153276831E-02 - 9.5930005959E-03 7.4208862241E-03 1.0204771159E-02 - 1.0268317980E-02 7.5691768772E-03 1.0360942246E-02 - 1.1728038434E-02 7.5586109671E-03 1.1490286644E-02 - 1.1329869499E-02 7.2868697753E-03 1.2046683365E-02 -:LATVEC_SCALE: 3.0961105795E+01 3.0961105795E+01 2.0640737197E+01 -:STRIO: - -6.8131982891E-01 4.6689146648E-02 -9.4123059660E-02 - 4.6689146648E-02 -6.7531531608E-01 -1.3117995111E-01 - -9.4123059660E-02 -1.3117995111E-01 -6.1669435364E-01 -:STRESS: - -1.5695254723E+01 -5.1652006875E+00 -3.9574473360E+00 - -5.1652006875E+00 -8.7116999171E+00 -4.6908065537E+00 - -3.9574473360E+00 -4.6908065537E+00 -1.5385013549E+01 -:PRESIO: 6.5777649954E-01 -:PRES: 1.3263989396E+01 -:PRESIG: 6.7607551579E-01 -:MIND: -Si - Si: 7.2005265945E+00 -Al - Al: 7.2082420250E+00 -Si - Al: 4.2387322698E+00 -:MDSTEP: 4 -:MDTM: 7.62 -:TWIST: 0 -:TEL: 1000 -:TIO: 994.932830731549 -:TEN: -3.2422713562E+00 -:KEN: 4.5948653234E-03 -:KENIG: 4.7261471898E-03 -:FEN: -3.2468662215E+00 -:UEN: -3.2459659865E+00 -:TSEN: -9.0023500100E-04 -:NPT_NP_HAMIL: 4.4254718862E-06 -:R: - 1.0795336334E-01 1.3321260219E-01 1.3863576711E-01 - 5.2693214841E+00 5.2640348356E+00 1.4132176212E-01 - 1.0451540877E+01 1.0415227327E+01 1.1296898344E-01 - 9.6829466143E-02 5.2601217026E+00 5.2633374770E+00 - 5.2778255878E+00 1.0438570811E+01 5.2775899476E+00 - 1.0423458619E+01 1.5598734160E+01 5.2766916652E+00 - 8.0907625081E-02 1.0415099683E+01 1.0458563784E+01 - 5.2694790970E+00 1.5599802554E+01 1.0462905800E+01 - 1.0445016634E+01 2.0740406827E+01 1.0454463938E+01 - 5.2017602482E+00 1.0850142516E-01 5.2113062786E+00 - 1.0377651842E+01 5.2699468223E+00 5.2219637555E+00 - 1.5541725034E+01 1.0414359672E+01 5.2474704588E+00 - 5.2359837624E+00 5.2630281832E+00 1.0400798062E+01 - 1.0403950210E+01 1.0436456059E+01 1.0385969937E+01 - 1.5514443838E+01 1.5605533761E+01 1.0377506755E+01 - 5.2192454303E+00 1.0406519078E+01 1.5556372502E+01 - 1.0365973230E+01 1.5615648259E+01 1.5557429487E+01 - 1.5533522024E+01 2.0756886993E+01 1.5543638975E+01 - 2.5864272597E+00 2.5862874152E+00 2.5873361656E+00 - 7.7331564853E+00 7.7408950683E+00 2.5775343010E+00 - 1.2911264411E+01 1.2886669069E+01 2.5555586197E+00 - 2.5739060110E+00 7.7311145219E+00 7.7256905987E+00 - 7.7372723921E+00 1.2888465717E+01 7.7435823336E+00 - 1.2888455407E+01 1.8059599471E+01 7.7302253951E+00 - 2.5885053692E+00 1.2917722816E+01 1.2913530080E+01 - 7.7148351926E+00 1.8063160054E+01 1.2907163566E+01 - 1.2911109144E+01 2.3216847091E+01 1.2889662505E+01 - 7.6902267948E+00 2.5693065737E+00 7.7050555627E+00 - 1.2862861718E+01 7.7336615705E+00 7.6926774330E+00 - 1.8001139491E+01 1.2909413696E+01 7.6991499833E+00 - 7.6858134844E+00 7.7345928304E+00 1.2849356140E+01 - 1.2844718783E+01 1.2876168051E+01 1.2818980590E+01 - 1.8017367399E+01 1.8071520262E+01 1.2862913145E+01 - 7.7003573788E+00 1.2905989196E+01 1.8020544066E+01 - 1.2856668647E+01 1.8078254311E+01 1.8017448511E+01 - 1.8004260827E+01 2.3227944569E+01 1.8018508420E+01 -:V: - -1.2270450917E-05 4.9843539122E-04 2.9414996261E-04 - 1.8318100362E-05 -8.7202227688E-05 3.4839339650E-04 - 4.3805152754E-04 -2.9329158351E-04 -2.2358202696E-04 - -2.3656260585E-04 -7.2301584071E-05 -3.2086933088E-04 - 1.8959208589E-04 3.0268758488E-04 -3.3649332874E-05 - -1.2819099801E-04 2.7734977517E-04 -5.1983861191E-05 - -5.5674732450E-04 -3.8910215538E-04 1.7384791163E-04 - 2.1542541945E-05 1.1148215617E-04 2.6068584151E-04 - 3.0643948784E-04 -3.0795452143E-04 9.0912981248E-05 - -3.1135199833E-04 -1.4284667700E-06 -4.3117154705E-04 - 1.1693458581E-05 3.0584473434E-05 -2.1639740150E-04 - 6.5639740107E-05 -3.1201230299E-04 2.9786481472E-04 - 3.7814690717E-04 -1.5385766718E-05 2.5958737452E-04 - 5.4149372978E-04 2.5783142752E-04 -3.9597583852E-05 - -4.8428946137E-04 4.1378727823E-04 -2.0938873658E-04 - 4.1354467049E-05 -5.6392505059E-04 -4.4941237607E-05 - -2.2328344490E-04 4.2979637155E-04 -2.4020318721E-05 - -9.9477924357E-05 2.3162580843E-05 -3.0172987642E-04 - 1.2786758451E-04 1.2774952785E-04 1.4630631653E-04 - -1.3667553257E-04 2.2142925391E-05 -5.1360067795E-05 - 2.0029596744E-04 -2.9327252926E-04 -4.9426098934E-04 - -1.2471000054E-04 -8.1603464208E-05 -1.9330120712E-04 - -5.3922684474E-05 -1.3187111278E-04 1.6779262078E-04 - -2.6009311180E-04 6.4471270856E-05 -1.0200603917E-04 - 1.6932109008E-04 2.3888427353E-04 1.5209667384E-04 - -5.0609244495E-04 -5.0996317663E-05 2.3996162202E-05 - 1.9682515164E-04 -2.0721379192E-04 -3.2895245846E-04 - 2.9395887065E-05 -2.1680986203E-04 3.2841947500E-04 - 2.8732612721E-04 -1.2600387677E-04 7.9169624985E-05 - -1.7890955496E-04 1.6374783623E-04 2.0992665441E-04 - -5.9196318593E-05 -1.2596957279E-05 1.0890785245E-04 - -7.8156878602E-05 -3.8105158370E-04 -5.0274677762E-04 - 1.4788694865E-04 3.0274699428E-04 3.8203037494E-04 - 2.3372116272E-04 7.4107376087E-07 1.1854986494E-04 - 1.6268940956E-04 2.5120160600E-04 5.6403536417E-05 - -1.1603802593E-04 1.4843140043E-05 7.7950266676E-05 -:F: - -1.2217124884E-02 -9.3029068649E-03 -1.3542401942E-02 - -1.2190428799E-02 -8.6935534785E-03 -1.3288306814E-02 - -1.4006861035E-02 -9.3176511104E-03 -1.2764667185E-02 - -1.1220489290E-02 -7.9325735328E-03 -1.0727374393E-02 - -1.3847794885E-02 -9.2925488982E-03 -1.2715734931E-02 - -1.1793091540E-02 -1.1310639138E-02 -1.3914099942E-02 - -5.9285865943E-03 -6.0733882253E-03 -1.2165367743E-02 - -1.2541021123E-02 -1.0738463073E-02 -1.6383325409E-02 - -1.4412760214E-02 -9.6920086766E-03 -1.3298781752E-02 - -2.4212000364E-03 -1.2312376645E-02 -2.5041386662E-03 - -5.6788834924E-03 -1.3009391888E-02 -3.9823929463E-03 - -5.5072371542E-03 -1.2025097830E-02 -6.2373067060E-03 - -8.0887929406E-03 -1.3526285886E-02 -8.0801409879E-03 - -1.0263562157E-02 -1.7478982267E-02 -8.1393697424E-03 - -2.4772218242E-03 -1.1559345117E-02 -2.7068179356E-03 - -3.5752466417E-03 -1.1454104195E-02 -4.8738061379E-03 - -2.5873713461E-03 -1.4509723098E-02 -7.0846949879E-03 - -3.8977005023E-03 -1.3498613210E-02 -4.1367748228E-03 - 5.5577097751E-03 1.4017492756E-02 5.8280749170E-03 - 6.8049313126E-03 1.5088068931E-02 6.4724006710E-03 - 6.1417941975E-03 1.4520444938E-02 9.0998219549E-03 - 6.4800728244E-03 1.3939079755E-02 7.5441474384E-03 - 5.7970706566E-03 1.4909055650E-02 8.0775071929E-03 - 5.7962577130E-03 1.4699854736E-02 6.4297138219E-03 - 3.0136452393E-03 1.0722310531E-02 4.7818559922E-03 - 8.1449373761E-03 1.5858868376E-02 6.7320236654E-03 - 4.2306270330E-03 1.2758277809E-02 7.6051554598E-03 - 1.0101321961E-02 7.5555099115E-03 8.8420964063E-03 - 1.0082340153E-02 7.2194680270E-03 1.1620655485E-02 - 1.1839158525E-02 8.2034692864E-03 1.2380824268E-02 - 1.3099889962E-02 1.1490768860E-02 1.1202490868E-02 - 1.3924988639E-02 1.3224600302E-02 1.7939900774E-02 - 9.0089826680E-03 6.5523503402E-03 8.9469578184E-03 - 9.6481259786E-03 7.1580139038E-03 9.6155577580E-03 - 1.1770155385E-02 7.0865838210E-03 1.1318748713E-02 - 1.1213365058E-02 6.7234352011E-03 1.2107569840E-02 -:LATVEC_SCALE: 3.0962209575E+01 3.0962209575E+01 2.0641473050E+01 -:STRIO: - -6.8092321940E-01 4.8128149207E-02 -9.3986186724E-02 - 4.8128149207E-02 -6.7385198683E-01 -1.3051758611E-01 - -9.3986186724E-02 -1.3051758611E-01 -6.1665388590E-01 -:STRESS: - -1.5688194542E+01 -5.1562067584E+00 -3.9809197979E+00 - -5.1562067584E+00 -8.7028425404E+00 -4.6917019105E+00 - -3.9809197979E+00 -4.6917019105E+00 -1.5385092662E+01 -:PRESIO: 6.5714303071E-01 -:PRES: 1.3258709915E+01 -:PRESIG: 6.7457704571E-01 -:MIND: -Si - Si: 7.1888431156E+00 -Al - Al: 7.2004046644E+00 -Si - Al: 4.2224503159E+00 -:MDSTEP: 5 -:MDTM: 8.34 -:TWIST: 0 -:TEL: 1000 -:TIO: 993.219787514495 -:TEN: -3.2422683857E+00 -:KEN: 4.5869540327E-03 -:KENIG: 4.7180098622E-03 -:FEN: -3.2468553397E+00 -:UEN: -3.2459554076E+00 -:TSEN: -8.9993206065E-04 -:NPT_NP_HAMIL: 6.8443786141E-06 -:R: - 1.0769006125E-01 1.4141927477E-01 1.4343870080E-01 - 5.2698091615E+00 5.2627943865E+00 1.4702401828E-01 - 1.0459211790E+01 1.0410816406E+01 1.0920536469E-01 - 9.2858483956E-02 5.2591317718E+00 5.2582184661E+00 - 5.2811397325E+00 1.0444025771E+01 5.2772150439E+00 - 1.0421767596E+01 1.5604003417E+01 5.2760068392E+00 - 7.1664486551E-02 1.0409120245E+01 1.0461871779E+01 - 5.2700182784E+00 1.5602329482E+01 1.0467628791E+01 - 1.0450506627E+01 2.0736240390E+01 1.0456392941E+01 - 5.1968402579E+00 1.0841709619E-01 5.2044030452E+00 - 1.0378306703E+01 5.2706331838E+00 5.2186080632E+00 - 1.5543518396E+01 1.0409624370E+01 5.2526159823E+00 - 5.2424476715E+00 5.2629505545E+00 1.0405544320E+01 - 1.0413351055E+01 1.0441124693E+01 1.0385763069E+01 - 1.5507149684E+01 1.5613060323E+01 1.0374518149E+01 - 5.2201580922E+00 1.0397616799E+01 1.5556339608E+01 - 1.0362754732E+01 1.5623424509E+01 1.5557731107E+01 - 1.5532590575E+01 2.0758181632E+01 1.5539359055E+01 - 2.5886971913E+00 2.5886024651E+00 2.5899128425E+00 - 7.7312984847E+00 7.7417122918E+00 2.5768423274E+00 - 1.2915225597E+01 1.2882506177E+01 2.5475493352E+00 - 2.5719998208E+00 7.7302076786E+00 7.7228990906E+00 - 7.7367787019E+00 1.2886976587E+01 7.7467714625E+00 - 1.2884793235E+01 1.8061604032E+01 7.7289390166E+00 - 2.5914473794E+00 1.2922348512E+01 1.2916686011E+01 - 7.7068691964E+00 1.8063260015E+01 1.2908209730E+01 - 1.2915002238E+01 2.3214588259E+01 1.2884870697E+01 - 7.6911339172E+00 2.5658817146E+00 7.7109058152E+00 - 1.2868283062E+01 7.7319825379E+00 7.6944169810E+00 - 1.7999096926E+01 1.2912781324E+01 7.7030583573E+00 - 7.6852707076E+00 7.7348147220E+00 1.2851829901E+01 - 1.2844111181E+01 1.2870544532E+01 1.2811366305E+01 - 1.8020718985E+01 1.8077423984E+01 1.2869895717E+01 - 7.7046444489E+00 1.2906652757E+01 1.8023413591E+01 - 1.2860036105E+01 1.8083308146E+01 1.8019298722E+01 - 1.8003255576E+01 2.3229328163E+01 1.8020719712E+01 -:V: - -1.6246865834E-05 4.9635571121E-04 2.9031688866E-04 - 1.4407444992E-05 -9.0178329949E-05 3.4474384195E-04 - 4.3433687277E-04 -2.9685449399E-04 -2.2813022844E-04 - -2.4063534609E-04 -7.5003605512E-05 -3.2493993067E-04 - 1.8546493597E-04 3.0024572020E-04 -3.7827022225E-05 - -1.3224666267E-04 2.7420753449E-04 -5.6583582975E-05 - -5.5970549604E-04 -3.9179412710E-04 1.7023580016E-04 - 1.7524455035E-05 1.0821533479E-04 2.5587094511E-04 - 3.0234771241E-04 -3.1166595659E-04 8.6779221867E-05 - -3.1271692061E-04 -5.4154593049E-06 -4.3278705779E-04 - 9.8775896447E-06 2.6431704994E-05 -2.1809021408E-04 - 6.3980154967E-05 -3.1648631081E-04 2.9640263036E-04 - 3.7623549344E-04 -1.9791647877E-05 2.5745736428E-04 - 5.3918358511E-04 2.5265664271E-04 -4.2305454253E-05 - -4.8599545334E-04 4.1081933685E-04 -2.1065568106E-04 - 4.0274730351E-05 -5.6868470113E-04 -4.6602339688E-05 - -2.2453768285E-04 4.2590357343E-04 -2.6357804196E-05 - -1.0092499649E-04 1.8837639263E-05 -3.0363199607E-04 - 1.2997844158E-04 1.3270978834E-04 1.4854267659E-04 - -1.3463856077E-04 2.7266594428E-05 -4.9275789989E-05 - 2.0273882131E-04 -2.8892906287E-04 -4.9211874805E-04 - -1.2276011100E-04 -7.7060559303E-05 -1.9112097703E-04 - -5.2070672662E-05 -1.2709534675E-04 1.7082681094E-04 - -2.5862637341E-04 6.9543215744E-05 -1.0003071570E-04 - 1.7065240492E-04 2.4294210430E-04 1.5399143456E-04 - -5.0429394432E-04 -4.5749588890E-05 2.6308611460E-05 - 1.9861775971E-04 -2.0330319547E-04 -3.2700499134E-04 - 3.2853346303E-05 -2.1466970428E-04 3.3201116435E-04 - 2.9125884765E-04 -1.2380734284E-04 8.3231808757E-05 - -1.7525570306E-04 1.6681690275E-04 2.1448906992E-04 - -5.4894246640E-05 -8.7498885390E-06 1.1288471287E-04 - -7.3612284097E-05 -3.7730853160E-04 -4.9764265847E-04 - 1.5119772882E-04 3.0551945688E-04 3.8575749839E-04 - 2.3740751977E-04 3.1535889037E-06 1.2201018242E-04 - 1.6695791502E-04 2.5405776666E-04 6.0321511766E-05 - -1.1247756321E-04 1.7135604114E-05 8.2174187428E-05 -:F: - -1.2297921840E-02 -9.6228935696E-03 -1.3902385903E-02 - -1.2242823358E-02 -8.8004526960E-03 -1.3580984522E-02 - -1.4643176743E-02 -9.6177113252E-03 -1.2911441097E-02 - -1.0912690924E-02 -7.8216815109E-03 -1.0174801454E-02 - -1.4413879273E-02 -9.6238325925E-03 -1.2837247789E-02 - -1.1663040779E-02 -1.2265592172E-02 -1.4422840572E-02 - -4.1571958530E-03 -5.0373251488E-03 -1.1877655361E-02 - -1.2976045060E-02 -1.1273769216E-02 -1.7411261003E-02 - -1.5421049709E-02 -9.8271068314E-03 -1.3295196493E-02 - -1.4789174312E-03 -1.1991835116E-02 -1.4684934155E-03 - -5.8183903947E-03 -1.2869773935E-02 -3.4500410873E-03 - -5.5467611428E-03 -1.1530319603E-02 -6.4773396324E-03 - -8.9793197219E-03 -1.3602005099E-02 -8.9095324518E-03 - -1.1964664141E-02 -1.8914165188E-02 -9.0978918010E-03 - -1.5040256478E-03 -1.0979975966E-02 -1.7944044043E-03 - -3.3006590542E-03 -1.0534972561E-02 -4.3394720415E-03 - -1.9771684077E-03 -1.4577423492E-02 -7.2371405082E-03 - -3.6676232987E-03 -1.3222692324E-02 -3.3574026744E-03 - 5.4734910621E-03 1.4265762548E-02 5.7354667190E-03 - 7.1257411762E-03 1.5653532860E-02 6.6228339856E-03 - 6.2993518840E-03 1.4925133842E-02 1.0066791673E-02 - 6.9374105105E-03 1.3899942308E-02 7.7357063937E-03 - 6.0223105126E-03 1.5148995348E-02 8.4765838436E-03 - 6.0476208968E-03 1.4897368164E-02 6.2301959833E-03 - 2.1262285054E-03 9.8871795899E-03 4.3955123829E-03 - 8.9057430700E-03 1.6691608862E-02 6.9862770380E-03 - 3.6695718330E-03 1.2539203789E-02 8.1267114381E-03 - 9.6210719084E-03 7.2768120368E-03 7.8241522312E-03 - 9.5626127063E-03 6.7830880118E-03 1.1560942826E-02 - 1.1937766896E-02 8.1221017860E-03 1.2520263652E-02 - 1.3847305279E-02 1.2226065371E-02 1.0688132844E-02 - 1.5044441303E-02 1.4575546657E-02 1.9738658210E-02 - 8.4290532361E-03 5.6990533382E-03 7.6845671125E-03 - 9.0325130563E-03 6.7538623195E-03 8.8739766946E-03 - 1.1799831704E-02 6.6107188614E-03 1.1130782637E-02 - 1.1083287240E-02 6.1575526558E-03 1.2147976546E-02 -:LATVEC_SCALE: 3.0963676503E+01 3.0963676503E+01 2.0642451002E+01 -:STRIO: - -6.8084449713E-01 4.9837419670E-02 -9.3798158114E-02 - 4.9837419670E-02 -6.7329989694E-01 -1.2993073709E-01 - -9.3798158114E-02 -1.2993073709E-01 -6.1704661537E-01 -:STRESS: - -1.5677094184E+01 -5.1429907041E+00 -3.9987766270E+00 - -5.1429907041E+00 -8.6938971867E+00 -4.6890775742E+00 - -3.9987766270E+00 -4.6890775742E+00 -1.5382210650E+01 -:PRESIO: 6.5706366981E-01 -:PRES: 1.3251067340E+01 -:PRESIG: 6.7331987452E-01 -:MIND: -Si - Si: 7.1773183685E+00 -Al - Al: 7.1927210421E+00 -Si - Al: 4.2064505946E+00 -:MDSTEP: 6 -:MDTM: 7.67 -:TWIST: 0 -:TEL: 1000 -:TIO: 992.390059429669 -:TEN: -3.2422594031E+00 -:KEN: 4.5831221270E-03 -:KENIG: 4.7140684735E-03 -:FEN: -3.2468425253E+00 -:UEN: -3.2459427308E+00 -:TSEN: -8.9979442651E-04 -:NPT_NP_HAMIL: 9.3338828544E-06 -:R: - 1.0736157946E-01 1.4959575530E-01 1.4818041989E-01 - 5.2702927636E+00 5.2615640542E+00 1.5266897469E-01 - 1.0466942321E+01 1.0406462482E+01 1.0536491533E-01 - 8.8820678494E-02 5.2581577514E+00 5.2530928755E+00 - 5.2844450909E+00 1.0449561714E+01 5.2768309033E+00 - 1.0420129273E+01 1.5609398069E+01 5.2753035388E+00 - 6.2377784803E-02 1.0403218527E+01 1.0465243762E+01 - 5.2705495884E+00 1.5604980520E+01 1.0472389627E+01 - 1.0456046752E+01 2.0732248451E+01 1.0458374984E+01 - 5.1919599762E+00 1.0826966187E-01 5.1975349109E+00 - 1.0379050651E+01 5.2713126019E+00 5.2152855332E+00 - 1.5545464069E+01 1.0404935045E+01 5.2577992328E+00 - 5.2489389673E+00 5.2628601476E+00 1.0410373244E+01 - 1.0422829466E+01 1.0445822701E+01 1.0385625767E+01 - 1.5500007277E+01 1.5620724668E+01 1.0371631380E+01 - 5.2211149598E+00 1.0388755701E+01 1.5556461256E+01 - 1.0359636407E+01 1.5631320016E+01 1.5558172585E+01 - 1.5531814837E+01 2.0759645943E+01 1.5535228560E+01 - 2.5910326288E+00 2.5910320809E+00 2.5925572328E+00 - 7.7295640862E+00 7.7427071263E+00 2.5762150267E+00 - 1.2919378986E+01 1.2878563675E+01 2.5396060319E+00 - 2.5701570906E+00 7.7294644207E+00 7.7202322479E+00 - 7.7364058018E+00 1.2885715551E+01 7.7501039842E+00 - 1.2881303251E+01 1.8063902810E+01 7.7277725966E+00 - 2.5944379007E+00 1.2927188061E+01 1.2920021632E+01 - 7.6990217989E+00 1.8063659639E+01 1.2909444857E+01 - 1.2919072728E+01 2.3212659205E+01 1.2880259947E+01 - 7.6921847009E+00 2.5625184964E+00 7.7169017939E+00 - 1.2873917741E+01 7.7304256361E+00 7.6963130230E+00 - 1.7997321688E+01 1.2916349853E+01 7.7071338617E+00 - 7.6848915817E+00 7.7351936363E+00 1.2854516012E+01 - 1.2843732714E+01 1.2865135820E+01 1.2803990128E+01 - 1.8024331534E+01 1.8083580232E+01 1.2877084926E+01 - 7.7090801561E+00 1.2907503053E+01 1.8026545432E+01 - 1.2863624338E+01 1.8088617614E+01 1.8021421325E+01 - 1.8002515427E+01 2.3231014899E+01 1.8023209941E+01 -:V: - -2.0276288468E-05 4.9464274424E-04 2.8663492202E-04 - 1.0482580067E-05 -9.3284001097E-05 3.4131993685E-04 - 4.3082233705E-04 -3.0080950257E-04 -2.3295772391E-04 - -2.4485079162E-04 -7.7749315126E-05 -3.2915483248E-04 - 1.8132069932E-04 2.9797772101E-04 -4.2092182820E-05 - -1.3639856234E-04 2.7101017997E-04 -6.1415394743E-05 - -5.6263528418E-04 -3.9453403741E-04 1.6687000325E-04 - 1.3370906484E-05 1.0486971023E-04 2.5095496984E-04 - 2.9820786079E-04 -3.1573068781E-04 8.2718193817E-05 - -3.1408053143E-04 -9.3150979028E-06 -4.3448692945E-04 - 8.0208733937E-06 2.2337774681E-05 -2.1982463235E-04 - 6.2364460804E-05 -3.2111637117E-04 2.9514295268E-04 - 3.7439120989E-04 -2.4253507967E-05 2.5529970311E-04 - 5.3683323188E-04 2.4724476397E-04 -4.5372054030E-05 - -4.8785734272E-04 4.0842483912E-04 -2.1183278612E-04 - 3.9319524974E-05 -5.7370573785E-04 -4.8139776361E-05 - -2.2581325512E-04 4.2238648117E-04 -2.8776570626E-05 - -1.0239847233E-04 1.4607912823E-05 -3.0557837592E-04 - 1.3219158562E-04 1.3789512055E-04 1.5089666200E-04 - -1.3261684376E-04 3.2621574017E-05 -4.7182174533E-05 - 2.0543623243E-04 -2.8471408456E-04 -4.9011659555E-04 - -1.2076829277E-04 -7.2591938059E-05 -1.8905336943E-04 - -5.0187439557E-05 -1.2234711757E-04 1.7416804426E-04 - -2.5731888187E-04 7.4762827789E-05 -9.8213053057E-05 - 1.7185201585E-04 2.4696293317E-04 1.5590904451E-04 - -5.0271769833E-04 -4.0251142322E-05 2.8738570254E-05 - 2.0041683920E-04 -1.9965046730E-04 -3.2518991919E-04 - 3.6190183292E-05 -2.1282343191E-04 3.3558835476E-04 - 2.9530691486E-04 -1.2187051930E-04 8.7365209262E-05 - -1.7172642270E-04 1.7002727382E-04 2.1931720343E-04 - -5.0380671943E-05 -4.6524155308E-06 1.1680770873E-04 - -6.8748021788E-05 -3.7346141776E-04 -4.9239509883E-04 - 1.5446741244E-04 3.0830519850E-04 3.8943965530E-04 - 2.4112452800E-04 5.4396875345E-06 1.2534731788E-04 - 1.7140869343E-04 2.5700532412E-04 6.4245071143E-05 - -1.0905880715E-04 1.9260197254E-05 8.6502524570E-05 -:F: - -1.2368005292E-02 -9.9370589181E-03 -1.4238023063E-02 - -1.2275428545E-02 -8.8937130809E-03 -1.3859802166E-02 - -1.5264744911E-02 -9.9122087053E-03 -1.3043917086E-02 - -1.0590390751E-02 -7.7084237930E-03 -9.6073152777E-03 - -1.4961922897E-02 -9.9450533048E-03 -1.2948980190E-02 - -1.1525130539E-02 -1.3202338589E-02 -1.4902591829E-02 - -2.3820601459E-03 -3.9946955237E-03 -1.1628854027E-02 - -1.3403378903E-02 -1.1806176653E-02 -1.8428888981E-02 - -1.6413659974E-02 -9.9484559845E-03 -1.3267183689E-02 - -5.3226447387E-04 -1.1687347905E-02 -4.2629777562E-04 - -5.9499694146E-03 -1.2718039932E-02 -2.9166359114E-03 - -5.5723937293E-03 -1.1023475711E-02 -6.7123533946E-03 - -9.8553454898E-03 -1.3676606208E-02 -9.7249642340E-03 - -1.3691188559E-02 -2.0366504289E-02 -1.0096419489E-02 - -5.4012047761E-04 -1.0417500485E-02 -8.8543248730E-04 - -3.0431324179E-03 -9.6098678413E-03 -3.8063519797E-03 - -1.3774392861E-03 -1.4623094589E-02 -7.3676581732E-03 - -3.4380798232E-03 -1.2935254135E-02 -2.5671419020E-03 - 5.3708754152E-03 1.4506107556E-02 5.6338390499E-03 - 7.4379041633E-03 1.6205526595E-02 6.7648657494E-03 - 6.4611645309E-03 1.5317101005E-02 1.1009241302E-02 - 7.3763417029E-03 1.3855170397E-02 7.9173539749E-03 - 6.2413035442E-03 1.5374073688E-02 8.8658143690E-03 - 6.2920470344E-03 1.5078809114E-02 6.0105114789E-03 - 1.2565210008E-03 9.0561451305E-03 4.0336483884E-03 - 9.6632307583E-03 1.7515079234E-02 7.2427447174E-03 - 3.0830468216E-03 1.2289516481E-02 8.6537775267E-03 - 9.1297314582E-03 7.0034210690E-03 6.7984875534E-03 - 9.0287926513E-03 6.3414119190E-03 1.1496719402E-02 - 1.2023936711E-02 8.0345703826E-03 1.2640231044E-02 - 1.4578256024E-02 1.2945649445E-02 1.0163098703E-02 - 1.6206311708E-02 1.5942242347E-02 2.1547299521E-02 - 7.8551858161E-03 4.8623134523E-03 6.4186891496E-03 - 8.4221488087E-03 6.3573880114E-03 8.1374615348E-03 - 1.1817102159E-02 6.1310447443E-03 1.0926709486E-02 - 1.0940755322E-02 5.5902450747E-03 1.2168318705E-02 -:LATVEC_SCALE: 3.0965500904E+01 3.0965500904E+01 2.0643667270E+01 -:STRIO: - -6.8120765571E-01 5.1829004742E-02 -9.3578608543E-02 - 5.1829004742E-02 -6.7378273041E-01 -1.2944925859E-01 - -9.3578608543E-02 -1.2944925859E-01 -6.1798643109E-01 -:STRESS: - -1.5662025504E+01 -5.1255249913E+00 -4.0109832515E+00 - -5.1255249913E+00 -8.6848768945E+00 -4.6829256963E+00 - -4.0109832515E+00 -4.6829256963E+00 -1.5376434945E+01 -:PRESIO: 6.5765893907E-01 -:PRES: 1.3241112448E+01 -:PRESIG: 6.7263848434E-01 -:MIND: -Si - Si: 7.1659493075E+00 -Al - Al: 7.1851914980E+00 -Si - Al: 4.1907439304E+00 -:MDSTEP: 7 -:MDTM: 8.32 -:TWIST: 0 -:TEL: 1000 -:TIO: 992.628063958591 -:TEN: -3.2422435565E+00 -:KEN: 4.5842212954E-03 -:KENIG: 4.7151990467E-03 -:FEN: -3.2468277778E+00 -:UEN: -3.2459279585E+00 -:TSEN: -8.9981938374E-04 -:NPT_NP_HAMIL: 1.1956871058E-05 -:R: - 1.0696701679E-01 1.5774784798E-01 1.5286332525E-01 - 5.2707707948E+00 5.2603404640E+00 1.5826018767E-01 - 1.0474733022E+01 1.0402156609E+01 1.0144309481E-01 - 8.4713792658E-02 5.2571976284E+00 5.2479571916E+00 - 5.2877400210E+00 1.0455178820E+01 5.2764347814E+00 - 1.0418539530E+01 1.5614913270E+01 5.2745767272E+00 - 1.5536885793E+01 2.5881228928E+01 1.0468680893E+01 - 5.2710694528E+00 1.5607750427E+01 1.0477183910E+01 - 1.0461633512E+01 2.0728420209E+01 1.0460408719E+01 - 5.1871182984E+00 1.0806039968E-01 5.1906994146E+00 - 1.0379880459E+01 5.2719847416E+00 5.2119942748E+00 - 1.5547558969E+01 1.0400286693E+01 5.2630221339E+00 - 5.2554573363E+00 5.2627546850E+00 1.0415281728E+01 - 1.0432381776E+01 1.0450543282E+01 1.0385549286E+01 - 1.5493010370E+01 1.5628532120E+01 1.0368845445E+01 - 5.2221166841E+00 1.0379929121E+01 1.5556735651E+01 - 1.0356615382E+01 1.5639337011E+01 1.5558748834E+01 - 1.5531190567E+01 2.0761276372E+01 1.5531243101E+01 - 2.5934344971E+00 2.5935793239E+00 2.5952705605E+00 - 7.7279511795E+00 7.7438814896E+00 2.5756519279E+00 - 1.2923725579E+01 1.2874836393E+01 2.5317258943E+00 - 2.5683778686E+00 7.7288816866E+00 7.7176863707E+00 - 7.7361523211E+00 1.2884679028E+01 7.7535829893E+00 - 1.2877979748E+01 1.8066493756E+01 7.7267215823E+00 - 2.5974741464E+00 1.2932237631E+01 1.2923534230E+01 - 7.6912876693E+00 1.8064358697E+01 1.2910867750E+01 - 1.2923317326E+01 2.3211049920E+01 1.2875825105E+01 - 7.6933752252E+00 2.5592115802E+00 7.7230412084E+00 - 1.2879764334E+01 7.7289847171E+00 7.6983648399E+00 - 1.7995807347E+01 1.2920118376E+01 7.7113788611E+00 - 7.6846777203E+00 7.7357317947E+00 1.2857410359E+01 - 1.2843585856E+01 1.2859940798E+01 1.2796851654E+01 - 1.8028199933E+01 1.8089984757E+01 1.2884476703E+01 - 7.7136630798E+00 1.2908534884E+01 1.8029933125E+01 - 1.2867433114E+01 1.8094179673E+01 1.8023811912E+01 - 1.8002033634E+01 2.3232996288E+01 1.8025976310E+01 -:V: - -2.4360643759E-05 4.9324500434E-04 2.8307591617E-04 - 6.5416463475E-06 -9.6511204137E-05 3.3808517238E-04 - 4.2746210127E-04 -3.0513204650E-04 -2.3804536760E-04 - -2.4918687433E-04 -8.0534981125E-05 -3.3348304292E-04 - 1.7713871444E-04 2.9585227859E-04 -4.6445320905E-05 - -1.4063781211E-04 2.6772932473E-04 -6.6473121481E-05 - -5.6548198258E-04 -3.9728374250E-04 1.6371528906E-04 - 9.0749507786E-06 1.0142891240E-04 2.4590576978E-04 - 2.9398620288E-04 -3.2011999771E-04 7.8722077245E-05 - -3.1541111268E-04 -1.3138375907E-05 -4.3622709984E-04 - 6.1215201465E-06 1.8297060854E-05 -2.2158068055E-04 - 6.0787880899E-05 -3.2587404998E-04 2.9405507055E-04 - 3.7257658914E-04 -2.8776764035E-05 2.5308825623E-04 - 5.3437399477E-04 2.4155372683E-04 -4.8812510630E-05 - -4.8983119199E-04 4.0655345596E-04 -2.1290087025E-04 - 3.8477941319E-05 -5.7893644355E-04 -4.9551254423E-05 - -2.2709238989E-04 4.1920315935E-04 -3.1271199260E-05 - -1.0389061358E-04 1.0468279837E-05 -3.0753729835E-04 - 1.3449141158E-04 1.4329870913E-04 1.5335419273E-04 - -1.3059584571E-04 3.8210493506E-05 -4.5073296321E-05 - 2.0837403791E-04 -2.8059499676E-04 -4.8820854454E-04 - -1.1872438328E-04 -6.8184084879E-05 -1.8707866189E-04 - -4.8266320760E-05 -1.1761015135E-04 1.7780202494E-04 - -2.5614434028E-04 8.0126906645E-05 -9.6546888407E-05 - 1.7290966005E-04 2.5092953929E-04 1.5784506307E-04 - -5.0131032656E-04 -3.4488991465E-05 3.1288633748E-05 - 2.0219617392E-04 -1.9623942174E-04 -3.2346864175E-04 - 3.9404495026E-05 -2.1124477702E-04 3.3911986715E-04 - 2.9944253670E-04 -1.2017991641E-04 9.1566957990E-05 - -1.6830204154E-04 1.7336547955E-04 2.2439134796E-04 - -4.5646915892E-05 -3.0098972125E-07 1.2066797547E-04 - -6.3532590601E-05 -3.6945858714E-04 -4.8693932400E-04 - 1.5768771413E-04 3.1108274451E-04 3.9304155430E-04 - 2.4485566223E-04 7.6050788241E-06 1.2855550823E-04 - 1.7602842831E-04 2.6002186594E-04 6.8169222184E-05 - -1.0576889372E-04 2.1217668713E-05 9.0927727367E-05 -:F: - -1.2425886420E-02 -1.0245773234E-02 -1.4549582707E-02 - -1.2286599393E-02 -8.9728876015E-03 -1.4125143966E-02 - -1.5871355400E-02 -1.0199704656E-02 -1.3161128785E-02 - -1.0253885148E-02 -7.5935325086E-03 -9.0240797014E-03 - -1.5491195034E-02 -1.0254968397E-02 -1.3049514437E-02 - -1.1378782749E-02 -1.4121497772E-02 -1.5352305945E-02 - -6.0393944789E-04 -2.9454067658E-03 -1.1421080690E-02 - -1.3822174781E-02 -1.2334164029E-02 -1.9434980199E-02 - -1.7391243750E-02 -1.0055595609E-02 -1.3214155175E-02 - 4.1779122310E-04 -1.1400409405E-02 6.2065450775E-04 - -6.0741037749E-03 -1.2555884207E-02 -2.3829697231E-03 - -5.5834944569E-03 -1.0504924655E-02 -6.9426429068E-03 - -1.0716417352E-02 -1.3749104269E-02 -1.0525977700E-02 - -1.5439567281E-02 -2.1832703416E-02 -1.1131773549E-02 - 4.1354605365E-04 -9.8733365036E-03 1.8358745030E-05 - -2.8044858589E-03 -8.6792928796E-03 -3.2747646836E-03 - -7.8803119564E-04 -1.4648029177E-02 -7.4765316156E-03 - -3.2098489880E-03 -1.2636710530E-02 -1.7660277289E-03 - 5.2503378154E-03 1.4737455901E-02 5.5234610497E-03 - 7.7415364743E-03 1.6742846950E-02 6.8973791951E-03 - 6.6255867616E-03 1.5695630316E-02 1.1926670206E-02 - 7.7964771349E-03 1.3805179252E-02 8.0896655390E-03 - 6.4529582039E-03 1.5584957539E-02 9.2438621876E-03 - 6.5288867830E-03 1.5243708217E-02 5.7704691935E-03 - 4.0555887301E-04 8.2306464225E-03 3.6970605392E-03 - 1.0415964615E-02 1.8328651903E-02 7.4997362139E-03 - 2.4704303207E-03 1.2007378196E-02 9.1862511459E-03 - 8.6287626408E-03 6.7366618504E-03 5.7651421394E-03 - 8.4821320418E-03 5.8940986291E-03 1.1427763200E-02 - 1.2098141639E-02 7.9412878846E-03 1.2741262783E-02 - 1.5291292939E-02 1.3648768984E-02 9.6265199791E-03 - 1.7406462082E-02 1.7323427716E-02 2.3363696093E-02 - 7.2880249262E-03 4.0435382124E-03 5.1508021723E-03 - 7.8181536351E-03 5.9701359572E-03 7.4074783017E-03 - 1.1822426499E-02 5.6484086010E-03 1.0707180616E-02 - 1.0786540370E-02 5.0211430834E-03 1.2169245706E-02 -:LATVEC_SCALE: 3.0967675147E+01 3.0967675147E+01 2.0645116765E+01 -:STRIO: - -6.8188177982E-01 5.4094895751E-02 -9.3313471899E-02 - 5.4094895751E-02 -6.7517477892E-01 -1.2905579335E-01 - -9.3313471899E-02 -1.2905579335E-01 -6.1935690438E-01 -:STRESS: - -1.5643033207E+01 -5.1037838244E+00 -4.0175350829E+00 - -5.1037838244E+00 -8.6757783954E+00 -4.6732493804E+00 - -4.0175350829E+00 -4.6732493804E+00 -1.5367821191E+01 -:PRESIO: 6.5880448771E-01 -:PRES: 1.3228877598E+01 -:PRESIG: 6.7265810095E-01 -:MIND: -Si - Si: 7.1547325840E+00 -Al - Al: 7.1778163894E+00 -Si - Al: 4.1753419757E+00 -:MDSTEP: 8 -:MDTM: 8.33 -:TWIST: 0 -:TEL: 1000 -:TIO: 993.747152430692 -:TEN: -3.2422217248E+00 -:KEN: 4.5893895446E-03 -:KENIG: 4.7205149602E-03 -:FEN: -3.2468111144E+00 -:UEN: -3.2459111143E+00 -:TSEN: -9.0000002262E-04 -:NPT_NP_HAMIL: 1.4716636763E-05 -:R: - 1.0650548727E-01 1.6587986477E-01 1.5748898935E-01 - 5.2712415037E+00 5.2591202730E+00 1.6380017451E-01 - 1.0482582672E+01 1.0397890185E+01 9.7436001277E-02 - 8.0536265328E-02 5.2562493233E+00 5.2428086274E+00 - 5.2910220865E+00 1.0460875908E+01 5.2760237674E+00 - 1.0416994121E+01 1.5620542659E+01 5.2738213357E+00 - 1.5528773237E+01 2.5876731337E+01 1.0472183064E+01 - 5.2715739483E+00 1.5610632874E+01 1.0482005935E+01 - 1.0467262001E+01 2.0724744828E+01 1.0462492114E+01 - 5.1823148208E+00 1.0779042333E-01 5.1838951532E+00 - 1.0380792398E+01 5.2726489183E+00 5.2087327822E+00 - 1.5549799160E+01 1.0395674747E+01 5.2682854862E+00 - 5.2620011315E+00 5.2626316183E+00 1.0420265441E+01 - 1.0442002039E+01 1.0455278187E+01 1.0385524247E+01 - 1.5486153381E+01 1.5636485946E+01 1.0366159464E+01 - 5.2231634447E+00 1.0371131548E+01 1.5557160407E+01 - 1.0353688909E+01 1.5647475787E+01 1.5559454199E+01 - 1.5530713084E+01 2.0763068348E+01 1.5527398522E+01 - 2.5959031672E+00 2.5962468201E+00 2.5980534952E+00 - 7.7264577102E+00 7.7452369232E+00 2.5751525872E+00 - 1.2928265272E+01 1.2871319465E+01 2.5239073779E+00 - 2.5666624021E+00 7.7284563647E+00 7.7152579751E+00 - 7.7360167018E+00 1.2883863265E+01 7.7572107368E+00 - 1.2874817196E+01 1.8069373830E+01 7.7257812895E+00 - 2.6005528172E+00 1.2937492188E+01 1.2927220226E+01 - 7.6836626492E+00 1.8065356374E+01 1.2912476613E+01 - 1.2927731456E+01 2.3209749841E+01 1.2871561487E+01 - 7.6947011341E+00 2.5559562177E+00 7.7293204495E+00 - 1.2885819987E+01 7.7276536508E+00 7.7005711849E+00 - 1.7994547193E+01 1.2924084946E+01 7.7157947452E+00 - 7.6846305743E+00 7.7364311152E+00 1.2860507923E+01 - 1.2843673077E+01 1.2854959083E+01 1.2789951582E+01 - 1.8032317907E+01 1.8096631731E+01 1.2892065299E+01 - 7.7183908533E+00 1.2909742551E+01 1.8033569127E+01 - 1.2871461160E+01 1.8099989750E+01 1.8026465081E+01 - 1.8001802977E+01 2.3235262761E+01 1.8029014954E+01 -:V: - -2.8495807024E-05 4.9203529489E-04 2.7956941426E-04 - 2.5841009730E-06 -9.9835478304E-05 3.3495210032E-04 - 4.2414562080E-04 -3.0974834980E-04 -2.4333480272E-04 - -2.5358099339E-04 -8.3343346146E-05 -3.3783949340E-04 - 1.7287276204E-04 2.9379363687E-04 -5.0877425783E-05 - -1.4493163068E-04 2.6429591726E-04 -7.1738047319E-05 - -5.6810132993E-04 -3.9994179203E-04 1.6071209033E-04 - 4.6301455756E-06 9.7862588223E-05 2.4065522447E-04 - 2.8960466795E-04 -3.2475378690E-04 7.4772984944E-05 - -3.1662731879E-04 -1.6892796158E-05 -4.3789527125E-04 - 4.1774105259E-06 1.4302542901E-05 -2.2330328839E-04 - 5.9237196307E-05 -3.3067825414E-04 2.9306319319E-04 - 3.7069707157E-04 -3.3360084238E-05 2.5075843315E-04 - 5.3165576297E-04 2.3550674648E-04 -5.2632675275E-05 - -4.9179627271E-04 4.0509303243E-04 -2.1380732642E-04 - 3.7733111737E-05 -5.8423296971E-04 -5.0825894452E-05 - -2.2832124573E-04 4.1624811209E-04 -3.3830485353E-05 - -1.0537707363E-04 6.4139919394E-06 -3.0942815696E-04 - 1.3684060172E-04 1.4888903259E-04 1.5587644339E-04 - -1.2854154805E-04 4.4027582829E-05 -4.2937517147E-05 - 2.1150422261E-04 -2.7649778514E-04 -4.8627369944E-04 - -1.1660065801E-04 -6.3814884973E-05 -1.8514887981E-04 - -4.6294287372E-05 -1.1285181861E-04 1.8168526786E-04 - -2.5503755455E-04 8.5617439455E-05 -9.5012213971E-05 - 1.7378762418E-04 2.5478405963E-04 1.5976986358E-04 - -4.9994173048E-04 -2.8448006640E-05 3.3955060722E-05 - 2.0389686641E-04 -1.9302605739E-04 -3.2175310537E-04 - 4.2486926762E-05 -2.0987541235E-04 3.4251984346E-04 - 3.0358988093E-04 -1.1870477977E-04 9.5818039217E-05 - -1.6493830141E-04 1.7678988625E-04 2.2965517546E-04 - -4.0679334139E-05 4.3063181212E-06 1.2443557072E-04 - -5.7927459038E-05 -3.6519257415E-04 -4.8113725153E-04 - 1.6082435335E-04 3.1378125344E-04 3.9646518229E-04 - 2.4854487133E-04 9.6535274507E-06 1.3160763221E-04 - 1.8077473969E-04 2.6304344270E-04 7.2076720181E-05 - -1.0258003141E-04 2.3004021912E-05 9.5426435604E-05 -:F: - -1.2471611198E-02 -1.0549192976E-02 -1.4835887002E-02 - -1.2276702374E-02 -9.0363211679E-03 -1.4375739474E-02 - -1.6461360667E-02 -1.0478271507E-02 -1.3261683011E-02 - -9.9037732477E-03 -7.4771797081E-03 -8.4267564412E-03 - -1.6000707604E-02 -1.0553694308E-02 -1.3137803912E-02 - -1.1222508448E-02 -1.5022744645E-02 -1.5772179759E-02 - 1.1760202436E-03 -1.8904117098E-03 -1.1255646524E-02 - -1.4230512782E-02 -1.2856680702E-02 -2.0427423444E-02 - -1.8352896385E-02 -1.0147350803E-02 -1.3135945198E-02 - 1.3696053985E-03 -1.1132336809E-02 1.6708973253E-03 - -6.1921726462E-03 -1.2382970570E-02 -1.8488992229E-03 - -5.5807554106E-03 -9.9740300586E-03 -7.1687309489E-03 - -1.1560434410E-02 -1.3818299515E-02 -1.1310713641E-02 - -1.7205428973E-02 -2.3309710660E-02 -1.2199606215E-02 - 1.3559236073E-03 -9.3488402886E-03 9.1563000294E-04 - -2.5859319118E-03 -7.7441371116E-03 -2.7456951150E-03 - -2.0859602864E-04 -1.4653497233E-02 -7.5648975263E-03 - -2.9835893067E-03 -1.2327475416E-02 -9.5568583708E-04 - 5.1110619228E-03 1.4959544841E-02 5.4050813380E-03 - 8.0359283629E-03 1.7265166660E-02 7.0202682622E-03 - 6.7911607365E-03 1.6059742385E-02 1.2818042746E-02 - 8.1977005318E-03 1.3750144802E-02 8.2528236005E-03 - 6.6567106414E-03 1.5780476568E-02 9.6096337552E-03 - 6.7581514741E-03 1.5391401187E-02 5.5088499129E-03 - -4.2538033422E-04 7.4107766579E-03 3.3871521888E-03 - 1.1162875734E-02 1.9129990512E-02 7.7556035862E-03 - 1.8318675823E-03 1.1692012705E-02 9.7234713221E-03 - 8.1189665383E-03 6.4781900333E-03 4.7256672763E-03 - 7.9223426136E-03 5.4422188616E-03 1.1355188473E-02 - 1.2160534719E-02 7.8424982264E-03 1.2823516608E-02 - 1.5985657766E-02 1.4334124623E-02 9.0766496586E-03 - 1.8639724489E-02 1.8715760173E-02 2.5184221536E-02 - 6.7290616749E-03 3.2440572714E-03 3.8821613746E-03 - 7.2211590713E-03 5.5927001960E-03 6.6853765103E-03 - 1.1815941663E-02 5.1629677259E-03 1.0472191931E-02 - 1.0621966955E-02 4.4513717604E-03 1.2150865863E-02 -:LATVEC_SCALE: 3.0970190200E+01 3.0970190200E+01 2.0646793467E+01 -:STRIO: - -6.8252560032E-01 5.6606950656E-02 -9.2961579495E-02 - 5.6606950656E-02 -6.7714403469E-01 -1.2869519766E-01 - -9.2961579495E-02 -1.2869519766E-01 -6.2085020883E-01 -:STRESS: - -1.5620269104E+01 -5.0777065243E+00 -4.0183755054E+00 - -5.0777065243E+00 -8.6667162539E+00 -4.6600036315E+00 - -4.0183755054E+00 -4.6600036315E+00 -1.5356532055E+01 -:PRESIO: 6.6017328128E-01 -:PRES: 1.3214505805E+01 -:PRESIG: 6.7325240663E-01 -:MIND: -Si - Si: 7.1436666844E+00 -Al - Al: 7.1705975705E+00 -Si - Al: 4.1602599664E+00 -:MDSTEP: 9 -:MDTM: 8.34 -:TWIST: 0 -:TEL: 1000 -:TIO: 995.254912851808 -:TEN: -3.2421962656E+00 -:KEN: 4.5963527846E-03 -:KENIG: 4.7276771499E-03 -:FEN: -3.2467926184E+00 -:UEN: -3.2458922909E+00 -:TSEN: -9.0032751855E-04 -:NPT_NP_HAMIL: 1.7587918835E-05 -:R: - 1.0597621265E-01 1.7399374144E-01 1.6205768744E-01 - 5.2717030439E+00 5.2579005208E+00 1.6928984147E-01 - 1.0490487797E+01 2.5880174028E+01 1.5579859072E+01 - 7.6287736943E-02 5.2553109985E+00 5.2376459058E+00 - 5.2942879120E+00 1.0466650181E+01 5.2755950535E+00 - 1.0415489246E+01 1.5626278285E+01 5.2730325676E+00 - 1.5520790804E+01 2.5872470594E+01 1.0475748894E+01 - 5.2720589710E+00 1.5613620680E+01 1.0486848562E+01 - 1.0472925679E+01 2.0721212590E+01 1.0464622613E+01 - 5.1775505598E+00 1.0746074757E-01 5.1771227272E+00 - 1.0381782494E+01 5.2733042431E+00 5.2055004929E+00 - 1.5552180141E+01 1.0391095989E+01 5.2735885680E+00 - 5.2685668467E+00 5.2624883671E+00 1.0425318653E+01 - 1.0451681350E+01 1.0460017596E+01 1.0385541033E+01 - 1.5479432691E+01 1.5644587016E+01 1.0363573337E+01 - 5.2242550137E+00 1.0362359997E+01 1.5557733030E+01 - 1.0350855061E+01 1.5655734355E+01 1.5560282920E+01 - 1.5530377860E+01 2.0765016812E+01 1.5523691859E+01 - 2.5984382433E+00 2.5990365021E+00 2.6009059118E+00 - 7.7250820845E+00 7.7467746542E+00 2.5747167113E+00 - 1.2932996760E+01 1.2868009111E+01 2.5161511440E+00 - 2.5650113972E+00 7.7281855599E+00 7.7129443058E+00 - 7.7359974540E+00 1.2883264813E+01 7.7609884780E+00 - 1.2871811017E+01 1.8072539241E+01 7.7249472424E+00 - 2.6036698373E+00 1.2942945307E+01 1.2931075191E+01 - 7.6761448428E+00 1.8066651702E+01 1.2914269283E+01 - 1.2932309173E+01 2.3208748742E+01 1.2867465774E+01 - 7.6961577182E+00 2.5527486895E+00 7.7357341211E+00 - 1.2892080127E+01 7.7264267184E+00 7.7029302646E+00 - 1.7993534954E+01 1.2928246545E+01 7.7203816540E+00 - 7.6847516533E+00 7.7372933542E+00 1.2863802824E+01 - 1.2843997194E+01 1.2850191978E+01 1.2783292854E+01 - 1.8036678138E+01 1.8103513595E+01 1.2899842836E+01 - 7.7232598636E+00 1.2911120139E+01 1.8037444985E+01 - 1.2875706111E+01 1.8106041676E+01 1.8029374709E+01 - 1.8001816371E+01 2.3237804191E+01 1.8032321175E+01 -:V: - -3.2672366003E-05 4.9085480851E-04 2.7602970962E-04 - -1.3875699802E-06 -1.0322250931E-04 3.3181410529E-04 - 4.2073739601E-04 -3.1455992375E-04 -2.4874683886E-04 - -2.5795017799E-04 -8.6149316901E-05 -3.4211343223E-04 - 1.6846883948E-04 2.9170821083E-04 -5.5372149147E-05 - -1.4923354262E-04 2.6062597412E-04 -7.7182623772E-05 - -5.7030884515E-04 -4.0237789805E-04 1.5779238608E-04 - 3.3842350465E-08 9.4136958678E-05 2.3512387204E-04 - 2.8496952705E-04 -3.2952637304E-04 7.0851511829E-05 - -3.1762593741E-04 -2.0581917613E-05 -4.3934880329E-04 - 2.1872614079E-06 1.0349797249E-05 -2.2492090124E-04 - 5.7696368007E-05 -3.3542160307E-04 2.9207276449E-04 - 3.6863547101E-04 -3.7995774824E-05 2.4823124406E-04 - 5.2849608228E-04 2.2901670815E-04 -5.6830979109E-05 - -4.9359765679E-04 4.0390579087E-04 -2.1448464905E-04 - 3.7066016150E-05 -5.8940834683E-04 -5.1948433178E-05 - -2.2942949505E-04 4.1339049601E-04 -3.6439265046E-05 - -1.0682541739E-04 2.4433011364E-06 -3.1114845789E-04 - 1.3919049900E-04 1.5462014617E-04 1.5841240031E-04 - -1.2641325223E-04 5.0059513484E-05 -4.0762121318E-05 - 2.1476184674E-04 -2.7233376683E-04 -4.8416060494E-04 - -1.1436330378E-04 -5.9461634234E-05 -1.8320531388E-04 - -4.4256980782E-05 -1.0803631128E-04 1.8575892698E-04 - -2.5391732631E-04 9.1206053705E-05 -9.3584625284E-05 - 1.7443598353E-04 2.5844820410E-04 1.6164201297E-04 - -4.9844995699E-04 -2.2116540191E-05 3.6729249740E-05 - 2.0544482864E-04 -1.8995681196E-04 -3.1993539979E-04 - 4.5422724579E-05 -2.0864391574E-04 3.4567695007E-04 - 3.0764923655E-04 -1.1740767359E-04 1.0008991931E-04 - -1.6158280466E-04 1.8024438825E-04 2.3503293838E-04 - -3.5465603805E-05 9.1672668026E-06 1.2806830210E-04 - -5.1895930513E-05 -3.6053571424E-04 -4.7482409495E-04 - 1.6383003198E-04 3.1630697407E-04 3.9958325032E-04 - 2.5211653795E-04 1.1586446694E-05 1.3446540213E-04 - 1.8558942534E-04 2.6598603590E-04 7.5942169712E-05 - -9.9459987410E-05 2.4612304080E-05 9.9965269474E-05 -:F: - -1.2503681558E-02 -1.0847759202E-02 -1.5097369409E-02 - -1.2244451753E-02 -9.0833522390E-03 -1.4611785720E-02 - -1.7034123197E-02 -1.0745759527E-02 -1.3344570969E-02 - -9.5400347425E-03 -7.3594130880E-03 -7.8150585335E-03 - -1.6489455524E-02 -1.0839701217E-02 -1.3212518025E-02 - -1.1056310792E-02 -1.5906497136E-02 -1.6161408134E-02 - 2.9564514945E-03 -8.2987633331E-04 -1.1134435509E-02 - -1.4627276495E-02 -1.3371638809E-02 -2.1404243282E-02 - -1.9298881942E-02 -1.0222858285E-02 -1.3031851507E-02 - 2.3219256464E-03 -1.0884443134E-02 2.7227574718E-03 - -6.3045710203E-03 -1.2200954436E-02 -1.3151722121E-03 - -5.5639189799E-03 -9.4310998524E-03 -7.3908301804E-03 - -1.2386403773E-02 -1.3882981137E-02 -1.2078532185E-02 - -1.8983681345E-02 -2.4792573099E-02 -1.3295014325E-02 - 2.2866700333E-03 -8.8451832725E-03 1.8050365400E-03 - -2.3888821437E-03 -6.8048151513E-03 -2.2195586798E-03 - 3.6095220985E-04 -1.4640473922E-02 -7.6327802426E-03 - -2.7603974537E-03 -1.2008632643E-02 -1.3652025295E-04 - 4.9533518811E-03 1.5171431576E-02 5.2790343115E-03 - 8.3207408824E-03 1.7771212449E-02 7.1325332309E-03 - 6.9559920117E-03 1.6408354735E-02 1.3682169593E-02 - 8.5795853984E-03 1.3690012658E-02 8.4068850392E-03 - 6.8512729468E-03 1.5960860257E-02 9.9613828835E-03 - 6.9796622305E-03 1.5520880385E-02 5.2255115214E-03 - -1.2352017675E-03 6.5983333329E-03 3.1047867267E-03 - 1.1902081709E-02 1.9917378483E-02 8.0084829794E-03 - 1.1669125600E-03 1.1342351738E-02 1.0265070394E-02 - 7.6015908477E-03 6.2292793918E-03 3.6806716699E-03 - 7.3507543142E-03 4.9855868044E-03 1.1279044060E-02 - 1.2211594632E-02 7.7385988571E-03 1.2887728861E-02 - 1.6660048129E-02 1.5000419806E-02 8.5126215924E-03 - 1.9900585803E-02 2.0115915143E-02 2.7004986004E-02 - 6.1786814296E-03 2.4645298410E-03 2.6140440906E-03 - 6.6325223853E-03 5.2265145058E-03 5.9726194746E-03 - 1.1798001180E-02 4.6752406791E-03 1.0222311629E-02 - 1.0447894763E-02 3.8811118402E-03 1.2113971092E-02 -:LATVEC_SCALE: 3.0973036400E+01 3.0973036400E+01 2.0648690934E+01 -:STRIO: - -6.8270796502E-01 5.9322972644E-02 -9.2471982832E-02 - 5.9322972644E-02 -6.7926803632E-01 -1.2829783747E-01 - -9.2471982832E-02 -1.2829783747E-01 -6.2207569427E-01 -:STRESS: - -1.5593756245E+01 -5.0472568608E+00 -4.0134897171E+00 - -5.0472568608E+00 -8.6576892151E+00 -4.6431792289E+00 - -4.0134897171E+00 -4.6431792289E+00 -1.5342602622E+01 -:PRESIO: 6.6135056520E-01 -:PRES: 1.3198016028E+01 -:PRESIG: 6.7408803145E-01 -:MIND: -Si - Si: 7.1307398386E+00 -Al - Al: 7.1635393771E+00 -Si - Al: 4.1455183600E+00 -:MDSTEP: 10 -:MDTM: 8.36 -:TWIST: 0 -:TEL: 1000 -:TIO: 996.526546079182 -:TEN: -3.2421702303E+00 -:KEN: 4.6022255262E-03 -:KENIG: 4.7337176841E-03 -:FEN: -3.2467724558E+00 -:UEN: -3.2458716650E+00 -:TSEN: -9.0079086697E-04 -:NPT_NP_HAMIL: 2.0482569877E-05 -:R: - 1.0537859587E-01 1.8208897121E-01 1.6656839990E-01 - 5.2721536384E+00 5.2566787975E+00 1.7472847286E-01 - 1.0498442849E+01 2.5877549725E+01 1.5577258230E+01 - 7.1969158172E-02 5.2543812133E+00 5.2324694834E+00 - 5.2975333189E+00 1.0472497406E+01 5.2751461143E+00 - 1.0414021838E+01 1.5632110903E+01 5.2722060891E+00 - 1.5512941566E+01 2.5868443078E+01 1.0479375928E+01 - 5.2725204043E+00 1.5616706158E+01 1.0491703458E+01 - 1.0478616572E+01 2.0717815418E+01 1.0466797379E+01 - 5.1728281191E+00 1.0707234022E-01 5.1703849338E+00 - 1.0382846750E+01 5.2739497713E+00 5.2022979481E+00 - 1.5554697161E+01 1.0386548875E+01 5.2789291988E+00 - 5.2751491832E+00 5.2623224971E+00 1.0430434425E+01 - 1.0461408006E+01 1.0464750387E+01 1.0385590073E+01 - 1.5472847062E+01 1.5652834052E+01 1.0361087989E+01 - 5.2253908531E+00 1.0353614386E+01 1.5558451251E+01 - 1.0348112983E+01 1.5664108708E+01 1.5561229474E+01 - 1.5530180848E+01 2.0767116680E+01 1.5520121727E+01 - 2.6010385570E+00 2.6019495507E+00 2.6038268797E+00 - 7.7238233098E+00 7.7484956494E+00 2.5743441781E+00 - 1.2937917691E+01 1.2864902866E+01 2.5084601598E+00 - 2.5634260570E+00 7.7280666900E+00 7.7107434888E+00 - 7.7360932786E+00 1.2882880728E+01 7.7649165110E+00 - 1.2868957857E+01 1.8075985692E+01 7.7242153129E+00 - 2.6068203648E+00 1.2948589327E+01 1.2935094048E+01 - 7.6687348228E+00 1.8068243823E+01 1.2916243423E+01 - 1.2937043352E+01 2.3208037155E+01 1.2863536283E+01 - 7.6977400157E+00 2.5495863758E+00 7.7422750796E+00 - 1.2898538604E+01 7.7252987561E+00 7.7054398104E+00 - 1.7992765121E+01 1.2932599253E+01 7.7251385167E+00 - 7.6850426060E+00 7.7383201847E+00 1.2867288480E+01 - 1.2844561527E+01 1.2845642698E+01 1.2776880887E+01 - 1.8041272544E+01 1.8110621317E+01 1.2907799441E+01 - 7.7282653099E+00 1.2912661732E+01 1.8041551627E+01 - 1.2880164657E+01 1.8112327948E+01 1.8032534233E+01 - 1.8002067190E+01 2.3240610301E+01 1.8035889705E+01 -:V: - -3.6878066288E-05 4.8956809440E-04 2.7238681961E-04 - -5.3668337159E-06 -1.0663937183E-04 3.2858255315E-04 - 4.1712440925E-04 -3.1947762715E-04 -2.5420837289E-04 - -2.6221912491E-04 -8.8929142403E-05 -3.4620556210E-04 - 1.6388493171E-04 2.8951813076E-04 -5.9911113710E-05 - -1.5349988870E-04 2.5665047039E-04 -8.2777635972E-05 - -5.7194408119E-04 -4.0447771130E-04 1.5489744849E-04 - -4.7121089060E-06 9.0226528254E-05 2.2924850023E-04 - 2.8000404436E-04 -3.3434249801E-04 6.6945399199E-05 - -3.1831752368E-04 -2.4207221148E-05 -4.4046408748E-04 - 1.5157088770E-07 6.4380440441E-06 -2.2637087048E-04 - 5.6153524884E-05 -3.4000764583E-04 2.9100339637E-04 - 3.6629349943E-04 -4.2673233628E-05 2.4544141070E-04 - 5.2474075152E-04 2.2201414321E-04 -6.1403347882E-05 - -4.9510123316E-04 4.0287329315E-04 -2.1487472790E-04 - 3.6459521707E-05 -5.9429770591E-04 -5.2904942062E-05 - -2.3035612404E-04 4.1052075209E-04 -3.9081643184E-05 - -1.0820706464E-04 -1.4420186502E-06 -3.1260826680E-04 - 1.4149669181E-04 1.6044764190E-04 1.6091603731E-04 - -1.2417805459E-04 5.6289393819E-05 -3.8538581310E-05 - 2.1808821972E-04 -2.6803085380E-04 -4.8174211514E-04 - -1.1198586361E-04 -5.5108406200E-05 -1.8119938642E-04 - -4.2144334334E-05 -1.0313709659E-04 1.8996841326E-04 - -2.5271512788E-04 9.6863083474E-05 -9.2245479128E-05 - 1.7481236409E-04 2.6185252253E-04 1.6342600055E-04 - -4.9669769029E-04 -1.5490153902E-05 3.9601170310E-05 - 2.0677358107E-04 -1.8699015905E-04 -3.1792390711E-04 - 4.8196768589E-05 -2.0748919261E-04 3.4849267293E-04 - 3.1153151262E-04 -1.1625793943E-04 1.0435470421E-04 - -1.5819348674E-04 1.8367805225E-04 2.4045494730E-04 - -3.0000094693E-05 1.4275293187E-05 1.3152602322E-04 - -4.5410691691E-05 -3.5538184844E-04 -4.6786341152E-04 - 1.6666216710E-04 3.1857833745E-04 4.0228396144E-04 - 2.5550359883E-04 1.3404387906E-05 1.3709435185E-04 - 1.9041844973E-04 2.6877513075E-04 7.9740192464E-05 - -9.6383734621E-05 2.6035100561E-05 1.0451148000E-04 -:F: - -1.2520667362E-02 -1.1141837636E-02 -1.5333151074E-02 - -1.2189480646E-02 -9.1128535565E-03 -1.4832380993E-02 - -1.7588476761E-02 -1.1000438549E-02 -1.3408663964E-02 - -9.1631118962E-03 -7.2409058278E-03 -7.1899764190E-03 - -1.6956477313E-02 -1.1112678626E-02 -1.3272339849E-02 - -1.0878950603E-02 -1.6772007349E-02 -1.6519375984E-02 - 4.7357857645E-03 2.3504931130E-04 -1.1058477124E-02 - -1.5010882017E-02 -1.3877217072E-02 -2.2362596686E-02 - -2.0228292601E-02 -1.0281093717E-02 -1.2901694457E-02 - 3.2726627130E-03 -1.0657803976E-02 3.7740135115E-03 - -6.4122272202E-03 -1.2010295695E-02 -7.8262997025E-04 - -5.5331472689E-03 -8.8760180052E-03 -7.6093615813E-03 - -1.3192733494E-02 -1.3941914370E-02 -1.2827527271E-02 - -2.0768189653E-02 -2.6276141351E-02 -1.4412318757E-02 - 3.2051333850E-03 -8.3628870347E-03 2.6851114124E-03 - -2.2148649394E-03 -5.8622841978E-03 -1.6972166655E-03 - 9.2036934157E-04 -1.4609926482E-02 -7.6807369413E-03 - -2.5409017796E-03 -1.1680615472E-02 6.8968065887E-04 - 4.7766181353E-03 1.5372010648E-02 5.1458966521E-03 - 8.5954624747E-03 1.8260009523E-02 7.2335835905E-03 - 7.1189582357E-03 1.6740421787E-02 1.4517699472E-02 - 8.9415366172E-03 1.3624873668E-02 8.5523392905E-03 - 7.0357478804E-03 1.6125285537E-02 1.0297870092E-02 - 7.1934609680E-03 1.5631507122E-02 4.9200840981E-03 - -2.0230548505E-03 5.7944021310E-03 2.8510396541E-03 - 1.2631842803E-02 2.0688262386E-02 8.2564230490E-03 - 4.7624439151E-04 1.0957660936E-02 1.0809775826E-02 - 7.0777126506E-03 5.9913795630E-03 2.6316820258E-03 - 6.7681461844E-03 4.5249073144E-03 1.1199799555E-02 - 1.2251470215E-02 7.6298109162E-03 1.2934145553E-02 - 1.7312929258E-02 1.5645962474E-02 7.9333818497E-03 - 2.1182543603E-02 2.1519034822E-02 2.8820612827E-02 - 5.6374183057E-03 1.7064580042E-03 1.3471989486E-03 - 6.0532951385E-03 4.8724986204E-03 5.2709242928E-03 - 1.1768566668E-02 4.1859946711E-03 9.9581698617E-03 - 1.0265553671E-02 3.3113894817E-03 1.2059015515E-02 -:LATVEC_SCALE: 3.0976204044E+01 3.0976204044E+01 2.0650802696E+01 -:STRIO: - -6.8206209968E-01 6.2197782407E-02 -9.1805394039E-02 - 6.2197782407E-02 -6.8118408659E-01 -1.2780864092E-01 - -9.1805394039E-02 -1.2780864092E-01 -6.2269891882E-01 -:STRESS: - -1.5563529418E+01 -5.0123886390E+00 -4.0028561400E+00 - -5.0123886390E+00 -8.6487174327E+00 -4.6227525952E+00 - -4.0028561400E+00 -4.6227525952E+00 -1.5326073900E+01 -:PRESIO: 6.6198170170E-01 -:PRES: 1.3179440250E+01 -:PRESIG: 6.7474227011E-01 -:MIND: -Si - Si: 7.1138982911E+00 -Al - Al: 7.1566487568E+00 -Si - Al: 4.1311427788E+00 diff --git a/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.refout b/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.refout deleted file mode 100644 index e870411a..00000000 --- a/tests/Al18Si18_NPTNP/standard/Al18Si18_NPTNP.refout +++ /dev/null @@ -1,551 +0,0 @@ -*************************************************************************** -* SPARC (version June 24, 2024) * -* Copyright (c) 2020 Material Physics & Mechanics Group, Georgia Tech * -* Distributed under GNU General Public License 3 (GPL) * -* Start time: Sun Aug 11 19:37:31 2024 * -*************************************************************************** - Input parameters -*************************************************************************** -LATVEC_SCALE: 30.96 30.96 20.64 -LATVEC: -0.500000000000000 0.500000000000000 0.000000000000000 -0.000000000000000 0.500000000000000 0.500000000000000 -0.500000000000000 0.000000000000000 0.500000000000000 -FD_GRID: 63 63 42 -FD_ORDER: 12 -BC: P P P -KPOINT_GRID: 1 1 1 -KPOINT_SHIFT: 0 0 0 -SPIN_TYP: 0 -ELEC_TEMP_TYPE: Fermi-Dirac -ELEC_TEMP: 1000 -EXCHANGE_CORRELATION: GGA_PBE -NSTATES: 80 -CHEB_DEGREE: 27 -CHEFSI_BOUND_FLAG: 0 -CALC_STRESS: 1 -TWTIME: 1E+09 -MD_FLAG: 1 -MD_METHOD: NPT_NP -MD_TIMESTEP: 0.4 -MD_NSTEP: 10 -ION_VEL_DSTR: 2 -ION_VEL_DSTR_RAND: 0 -ION_TEMP: 1000 -NPT_SCALE_VECS: 1 2 3 -NPT_SCALE_CONSTRAINTS: 123 -NPT_NP_QMASS: 500 -NPT_NP_BMASS: 0.05 -TARGET_PRESSURE: 12 GPa -MAXIT_SCF: 100 -MINIT_SCF: 2 -MAXIT_POISSON: 3000 -TOL_SCF: 5.00E-07 -POISSON_SOLVER: AAR -TOL_POISSON: 5.00E-09 -TOL_LANCZOS: 1.00E-02 -TOL_PSEUDOCHARGE: 5.00E-10 -MIXING_VARIABLE: potential -MIXING_PRECOND: kerker -TOL_PRECOND: 1.21E-04 -PRECOND_KERKER_KTF: 1 -PRECOND_KERKER_THRESH: 0.1 -MIXING_PARAMETER: 0.3 -MIXING_HISTORY: 7 -PULAY_FREQUENCY: 1 -PULAY_RESTART: 0 -REFERENCE_CUTOFF: 0.5 -RHO_TRIGGER: 4 -NUM_CHEFSI: 1 -FIX_RAND: 0 -VERBOSITY: 1 -PRINT_FORCES: 1 -PRINT_ATOMS: 1 -PRINT_EIGEN: 0 -PRINT_DENSITY: 0 -PRINT_MDOUT: 1 -PRINT_VELS: 1 -PRINT_RESTART: 1 -PRINT_RESTART_FQ: 1 -PRINT_ENERGY_DENSITY: 0 -OUTPUT_FILE: Al18Si18_NPTNP/temp_run/Al18Si18_NPTNP -*************************************************************************** - Cell -*************************************************************************** -Lattice vectors (Bohr): -15.480000000000000 15.480000000000000 0.000000000000000 -0.000000000000000 15.480000000000000 15.480000000000000 -10.320000000000000 0.000000000000000 10.320000000000000 -Volume: 4.9459714560E+03 (Bohr^3) -Density: 2.0040687695E-01 (amu/Bohr^3), 2.2457340241E+00 (g/cc) -*************************************************************************** - Parallelization -*************************************************************************** -NP_SPIN_PARAL: 1 -NP_KPOINT_PARAL: 1 -NP_BAND_PARAL: 16 -NP_DOMAIN_PARAL: 1 3 1 -NP_DOMAIN_PHI_PARAL: 4 4 3 -EIG_SERIAL_MAXNS: 1500 -*************************************************************************** - Initialization -*************************************************************************** -Number of processors : 48 -Mesh spacing : 0.347492 (Bohr) -Number of symmetry adapted k-points: 1 -Output printed to : Al18Si18_NPTNP/temp_run/Al18Si18_NPTNP.out -MD output printed to : Al18Si18_NPTNP/temp_run/Al18Si18_NPTNP.aimd -Total number of atom types : 2 -Total number of atoms : 36 -Total number of electrons : 126 -Atom type 1 (valence electrons) : Si 4 -Pseudopotential : ../psps/14_Si_4_1.9_1.9_pbe_n_v1.0.psp8 -Atomic mass : 28.0855 -Pseudocharge radii of atom type 1 : 8.69 8.69 8.69 (x, y, z dir) -Number of atoms of type 1 : 18 -Atom type 2 (valence electrons) : Al 3 -Pseudopotential : ../psps/13_Al_3_1.9_1.9_pbe_n_v1.0.psp8 -Atomic mass : 26.9815385 -Pseudocharge radii of atom type 2 : 9.03 9.03 9.03 (x, y, z dir) -Number of atoms of type 2 : 18 -Estimated total memory usage : 767.13 MB -Estimated memory per processor : 15.98 MB -=================================================================== - Self Consistent Field (SCF#1) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2223761380E+00 8.035E-02 2.656 -2 -3.2406418470E+00 3.204E-02 0.818 -3 -3.2446856712E+00 3.729E-02 0.785 -4 -3.2459046025E+00 3.314E-02 0.772 -5 -3.2465620714E+00 1.546E-02 0.776 -6 -3.2467316955E+00 1.864E-02 1.148 -7 -3.2468593143E+00 6.747E-03 0.788 -8 -3.2468780792E+00 3.830E-03 0.771 -9 -3.2468856999E+00 1.363E-03 0.766 -10 -3.2468866189E+00 1.239E-03 0.764 -11 -3.2468872352E+00 4.916E-04 0.749 -12 -3.2468873601E+00 1.401E-04 0.738 -13 -3.2468873818E+00 6.101E-05 0.727 -14 -3.2468873876E+00 2.899E-05 0.719 -15 -3.2468873887E+00 1.657E-05 0.712 -16 -3.2468873896E+00 6.431E-06 0.701 -17 -3.2468873894E+00 2.420E-06 0.693 -18 -3.2468873895E+00 1.273E-06 0.679 -19 -3.2468873896E+00 5.179E-07 0.672 -20 -3.2468873896E+00 3.431E-07 0.659 -Total number of SCF: 20 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468873896E+00 (Ha/atom) -Total free energy : -1.1688794603E+02 (Ha) -Band structure energy : -4.0134611980E+00 (Ha) -Exchange correlation energy : -4.7115100450E+01 (Ha) -Self and correction energy : -1.8563824223E+02 (Ha) --Entropy*kb*T : -3.2476338341E-02 (Ha) -Fermi level : 1.2923233023E-01 (Ha) -RMS force : 1.7392629966E-02 (Ha/Bohr) -Maximum force : 1.9646832787E-02 (Ha/Bohr) -Time for force calculation : 0.086 (sec) -Pressure : 1.3267457824E+01 (GPa) -Maximum stress : 1.5697144436E+01 (GPa) -Time for stress calculation : 0.209 (sec) -MD step time : 17.719 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9603687107265 30.9603687107265 20.640245807151 -CHEB_DEGREE: 27 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing : 0.347497 (Bohr) -=================================================================== - Self Consistent Field (SCF#2) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2465558335E+00 3.309E-02 0.813 -2 -3.2468465646E+00 9.720E-03 0.784 -3 -3.2468725292E+00 4.828E-03 0.779 -4 -3.2468814813E+00 1.223E-03 0.768 -5 -3.2468822292E+00 3.798E-04 0.814 -6 -3.2468823214E+00 2.297E-04 0.735 -7 -3.2468823424E+00 9.210E-05 0.730 -8 -3.2468823473E+00 3.790E-05 0.724 -9 -3.2468823479E+00 1.539E-05 0.716 -10 -3.2468823481E+00 8.143E-06 0.715 -11 -3.2468823480E+00 3.105E-06 0.698 -12 -3.2468823481E+00 1.337E-06 0.696 -13 -3.2468823481E+00 8.659E-07 0.672 -14 -3.2468823481E+00 3.262E-07 0.676 -Total number of SCF: 14 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468823481E+00 (Ha/atom) -Total free energy : -1.1688776453E+02 (Ha) -Band structure energy : -4.0142741385E+00 (Ha) -Exchange correlation energy : -4.7114935178E+01 (Ha) -Self and correction energy : -1.8563824204E+02 (Ha) --Entropy*kb*T : -3.2448025471E-02 (Ha) -Fermi level : 1.2922466158E-01 (Ha) -RMS force : 1.7452171778E-02 (Ha/Bohr) -Maximum force : 2.1414134604E-02 (Ha/Bohr) -Time for force calculation : 0.086 (sec) -Pressure : 1.3266891193E+01 (GPa) -Maximum stress : 1.5698232144E+01 (GPa) -Time for stress calculation : 0.209 (sec) -MD step time : 10.873 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9611057949962 30.9611057949962 20.6407371966641 -CHEB_DEGREE: 27 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing : 0.347505 (Bohr) -=================================================================== - Self Consistent Field (SCF#3) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2465493616E+00 3.306E-02 0.817 -2 -3.2468393222E+00 9.759E-03 0.787 -3 -3.2468654585E+00 4.813E-03 0.773 -4 -3.2468743542E+00 1.229E-03 0.763 -5 -3.2468751071E+00 3.800E-04 0.756 -6 -3.2468751996E+00 2.297E-04 0.734 -7 -3.2468752207E+00 9.110E-05 0.732 -8 -3.2468752256E+00 3.772E-05 0.723 -9 -3.2468752262E+00 1.529E-05 0.716 -10 -3.2468752263E+00 8.074E-06 0.707 -11 -3.2468752263E+00 3.143E-06 0.701 -12 -3.2468752263E+00 1.350E-06 0.689 -13 -3.2468752262E+00 8.653E-07 0.667 -14 -3.2468752263E+00 3.303E-07 0.671 -Total number of SCF: 14 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468752263E+00 (Ha/atom) -Total free energy : -1.1688750815E+02 (Ha) -Band structure energy : -4.0159227000E+00 (Ha) -Exchange correlation energy : -4.7114496552E+01 (Ha) -Self and correction energy : -1.8563824174E+02 (Ha) --Entropy*kb*T : -3.2425341635E-02 (Ha) -Fermi level : 1.2920946307E-01 (Ha) -RMS force : 1.7522682496E-02 (Ha/Bohr) -Maximum force : 2.3822528164E-02 (Ha/Bohr) -Time for force calculation : 0.085 (sec) -Pressure : 1.3263989396E+01 (GPa) -Maximum stress : 1.5695254723E+01 (GPa) -Time for stress calculation : 0.207 (sec) -MD step time : 10.782 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9622095746889 30.9622095746889 20.6414730497926 -CHEB_DEGREE: 27 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing : 0.347517 (Bohr) -=================================================================== - Self Consistent Field (SCF#4) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2468657462E+00 1.838E-03 0.751 -2 -3.2468661807E+00 1.278E-03 0.730 -3 -3.2468662108E+00 4.295E-04 0.732 -4 -3.2468662201E+00 6.778E-05 0.740 -5 -3.2468662212E+00 3.674E-05 0.702 -6 -3.2468662217E+00 2.120E-05 0.705 -7 -3.2468662219E+00 3.619E-06 0.707 -8 -3.2468662219E+00 2.525E-06 0.681 -9 -3.2468662218E+00 9.784E-07 0.683 -10 -3.2468662215E+00 3.929E-07 0.662 -Total number of SCF: 10 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468662215E+00 (Ha/atom) -Total free energy : -1.1688718397E+02 (Ha) -Band structure energy : -4.0184105375E+00 (Ha) -Exchange correlation energy : -4.7113784895E+01 (Ha) -Self and correction energy : -1.8563824137E+02 (Ha) --Entropy*kb*T : -3.2408460036E-02 (Ha) -Fermi level : 1.2918667337E-01 (Ha) -RMS force : 1.7605253590E-02 (Ha/Bohr) -Maximum force : 2.6279942951E-02 (Ha/Bohr) -Time for force calculation : 0.085 (sec) -Pressure : 1.3258709915E+01 (GPa) -Maximum stress : 1.5688194542E+01 (GPa) -Time for stress calculation : 0.207 (sec) -MD step time : 7.624 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9636765028389 30.9636765028389 20.6424510018926 -CHEB_DEGREE: 27 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing : 0.347534 (Bohr) -=================================================================== - Self Consistent Field (SCF#5) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2468547637E+00 3.142E-03 0.781 -2 -3.2468552623E+00 2.210E-03 0.730 -3 -3.2468553177E+00 4.579E-04 0.737 -4 -3.2468553360E+00 8.413E-05 0.718 -5 -3.2468553380E+00 4.418E-05 0.726 -6 -3.2468553386E+00 2.854E-05 0.709 -7 -3.2468553387E+00 5.596E-06 0.712 -8 -3.2468553385E+00 2.595E-06 0.693 -9 -3.2468553392E+00 1.192E-06 0.677 -10 -3.2468553383E+00 5.219E-07 0.668 -11 -3.2468553397E+00 3.387E-07 0.658 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468553397E+00 (Ha/atom) -Total free energy : -1.1688679223E+02 (Ha) -Band structure energy : -4.0217285969E+00 (Ha) -Exchange correlation energy : -4.7112802014E+01 (Ha) -Self and correction energy : -1.8563824094E+02 (Ha) --Entropy*kb*T : -3.2397554183E-02 (Ha) -Fermi level : 1.2915637550E-01 (Ha) -RMS force : 1.7702024688E-02 (Ha/Bohr) -Maximum force : 2.8781876284E-02 (Ha/Bohr) -Time for force calculation : 0.085 (sec) -Pressure : 1.3251067340E+01 (GPa) -Maximum stress : 1.5677094184E+01 (GPa) -Time for stress calculation : 0.208 (sec) -MD step time : 8.342 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9655009043114 30.9655009043114 20.6436672695409 -CHEB_DEGREE: 27 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing : 0.347554 (Bohr) -=================================================================== - Self Consistent Field (SCF#6) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2468419295E+00 3.158E-03 0.782 -2 -3.2468424496E+00 2.209E-03 0.735 -3 -3.2468425064E+00 4.781E-04 0.736 -4 -3.2468425232E+00 8.632E-05 0.718 -5 -3.2468425247E+00 4.503E-05 0.711 -6 -3.2468425255E+00 2.626E-05 0.706 -7 -3.2468425257E+00 5.200E-06 0.707 -8 -3.2468425256E+00 2.806E-06 0.692 -9 -3.2468425260E+00 1.057E-06 0.680 -10 -3.2468425253E+00 4.896E-07 0.667 -Total number of SCF: 10 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468425253E+00 (Ha/atom) -Total free energy : -1.1688633091E+02 (Ha) -Band structure energy : -4.0258601957E+00 (Ha) -Exchange correlation energy : -4.7111551990E+01 (Ha) -Self and correction energy : -1.8563824055E+02 (Ha) --Entropy*kb*T : -3.2392599354E-02 (Ha) -Fermi level : 1.2911873223E-01 (Ha) -RMS force : 1.7815677411E-02 (Ha/Bohr) -Maximum force : 3.1322288340E-02 (Ha/Bohr) -Time for force calculation : 0.086 (sec) -Pressure : 1.3241112448E+01 (GPa) -Maximum stress : 1.5662025504E+01 (GPa) -Time for stress calculation : 0.207 (sec) -MD step time : 7.671 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9676751470044 30.9676751470044 20.6451167646696 -CHEB_DEGREE: 27 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing : 0.347579 (Bohr) -=================================================================== - Self Consistent Field (SCF#7) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2468272291E+00 3.153E-03 0.749 -2 -3.2468276971E+00 2.235E-03 0.740 -3 -3.2468277537E+00 3.541E-04 0.747 -4 -3.2468277746E+00 9.069E-05 0.720 -5 -3.2468277769E+00 4.683E-05 0.716 -6 -3.2468277775E+00 2.930E-05 0.706 -7 -3.2468277778E+00 5.371E-06 0.708 -8 -3.2468277775E+00 2.518E-06 0.690 -9 -3.2468277779E+00 1.387E-06 0.681 -10 -3.2468277772E+00 5.578E-07 0.669 -11 -3.2468277778E+00 3.333E-07 0.660 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468277778E+00 (Ha/atom) -Total free energy : -1.1688580000E+02 (Ha) -Band structure energy : -4.0307878980E+00 (Ha) -Exchange correlation energy : -4.7110040610E+01 (Ha) -Self and correction energy : -1.8563824022E+02 (Ha) --Entropy*kb*T : -3.2393497815E-02 (Ha) -Fermi level : 1.2907393454E-01 (Ha) -RMS force : 1.7949676749E-02 (Ha/Bohr) -Maximum force : 3.3896140860E-02 (Ha/Bohr) -Time for force calculation : 0.088 (sec) -Pressure : 1.3228877598E+01 (GPa) -Maximum stress : 1.5643033207E+01 (GPa) -Time for stress calculation : 0.213 (sec) -MD step time : 8.326 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9701902002394 30.9701902002394 20.6467934668263 -CHEB_DEGREE: 27 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing : 0.347607 (Bohr) -=================================================================== - Self Consistent Field (SCF#8) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2468105348E+00 3.220E-03 0.749 -2 -3.2468110421E+00 2.260E-03 0.730 -3 -3.2468110967E+00 4.982E-04 0.732 -4 -3.2468111122E+00 6.966E-05 0.718 -5 -3.2468111135E+00 4.244E-05 0.708 -6 -3.2468111144E+00 2.284E-05 0.754 -7 -3.2468111146E+00 5.479E-06 0.710 -8 -3.2468111148E+00 3.327E-06 0.684 -9 -3.2468111146E+00 1.198E-06 0.681 -10 -3.2468111145E+00 5.817E-07 0.670 -11 -3.2468111144E+00 3.369E-07 0.657 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2468111144E+00 (Ha/atom) -Total free energy : -1.1688520012E+02 (Ha) -Band structure energy : -4.0364894061E+00 (Ha) -Exchange correlation energy : -4.7108275264E+01 (Ha) -Self and correction energy : -1.8563823997E+02 (Ha) --Entropy*kb*T : -3.2400000814E-02 (Ha) -Fermi level : 1.2902222233E-01 (Ha) -RMS force : 1.8107317983E-02 (Ha/Bohr) -Maximum force : 3.6496082286E-02 (Ha/Bohr) -Time for force calculation : 0.089 (sec) -Pressure : 1.3214505805E+01 (GPa) -Maximum stress : 1.5620269104E+01 (GPa) -Time for stress calculation : 0.214 (sec) -MD step time : 8.336 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.9730364003519 30.9730364003519 20.648690933568 -CHEB_DEGREE: 27 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing : 0.347639 (Bohr) -=================================================================== - Self Consistent Field (SCF#9) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2467920750E+00 3.130E-03 0.751 -2 -3.2467925471E+00 2.211E-03 0.728 -3 -3.2467925995E+00 4.018E-04 0.737 -4 -3.2467926158E+00 6.598E-05 0.717 -5 -3.2467926170E+00 4.177E-05 0.715 -6 -3.2467926178E+00 2.245E-05 0.711 -7 -3.2467926180E+00 4.598E-06 0.712 -8 -3.2467926180E+00 3.048E-06 0.685 -9 -3.2467926179E+00 9.433E-07 0.686 -10 -3.2467926171E+00 5.692E-07 0.691 -11 -3.2467926184E+00 3.299E-07 0.670 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2467926184E+00 (Ha/atom) -Total free energy : -1.1688453426E+02 (Ha) -Band structure energy : -4.0429423814E+00 (Ha) -Exchange correlation energy : -4.7106263221E+01 (Ha) -Self and correction energy : -1.8563823978E+02 (Ha) --Entropy*kb*T : -3.2411790668E-02 (Ha) -Fermi level : 1.2896381577E-01 (Ha) -RMS force : 1.8291421718E-02 (Ha/Bohr) -Maximum force : 3.9114608862E-02 (Ha/Bohr) -Time for force calculation : 0.088 (sec) -Pressure : 1.3198016028E+01 (GPa) -Maximum stress : 1.5593756245E+01 (GPa) -Time for stress calculation : 0.212 (sec) -MD step time : 8.341 (sec) -*************************************************************************** - Reinitialized parameters -*************************************************************************** -LATVEC_SCALE: 30.976204044497 30.976204044497 20.6508026963314 -CHEB_DEGREE: 27 -*************************************************************************** - Reinitialization -*************************************************************************** -Mesh spacing : 0.347674 (Bohr) -=================================================================== - Self Consistent Field (SCF#10) -=================================================================== -Iteration Free Energy (Ha/atom) SCF Error Timing (sec) -1 -3.2467719344E+00 3.193E-03 0.790 -2 -3.2467723794E+00 2.269E-03 0.732 -3 -3.2467724344E+00 2.993E-04 0.739 -4 -3.2467724528E+00 7.157E-05 0.718 -5 -3.2467724542E+00 4.139E-05 0.711 -6 -3.2467724550E+00 2.192E-05 0.723 -7 -3.2467724553E+00 5.147E-06 0.711 -8 -3.2467724553E+00 3.316E-06 0.691 -9 -3.2467724552E+00 1.055E-06 0.685 -10 -3.2467724548E+00 5.244E-07 0.670 -11 -3.2467724558E+00 2.955E-07 0.657 -Total number of SCF: 11 -==================================================================== - Energy and force calculation -==================================================================== -Free energy per atom : -3.2467724558E+00 (Ha/atom) -Total free energy : -1.1688380841E+02 (Ha) -Band structure energy : -4.0501270406E+00 (Ha) -Exchange correlation energy : -4.7104011769E+01 (Ha) -Self and correction energy : -1.8563823969E+02 (Ha) --Entropy*kb*T : -3.2428471211E-02 (Ha) -Fermi level : 1.2889888772E-01 (Ha) -RMS force : 1.8503718981E-02 (Ha/Bohr) -Maximum force : 4.1742026028E-02 (Ha/Bohr) -Time for force calculation : 0.087 (sec) -Pressure : 1.3179440250E+01 (GPa) -Maximum stress : 1.5563529418E+01 (GPa) -Time for stress calculation : 0.214 (sec) -MD step time : 8.366 (sec) -*************************************************************************** - Timing info -*************************************************************************** -Total walltime : 96.451 sec -___________________________________________________________________________ - -*************************************************************************** -* Material Physics & Mechanics Group, Georgia Tech * -* PI: Phanish Suryanarayana * -* List of contributors: See the documentation * -* Citation: See README.md or the documentation for details * -* Acknowledgements: U.S. DOE SC (DE-SC0019410), U.S. DOE NNSA (ASC) * -* {Preliminary developments: U.S. NSF (1333500,1663244,1553212)} * -*************************************************************************** - diff --git a/tests/Al18Si18_NPTNP/standard/esparallel.sbatch b/tests/Al18Si18_NPTNP/standard/esparallel.sbatch deleted file mode 100644 index d4b717c6..00000000 --- a/tests/Al18Si18_NPTNP/standard/esparallel.sbatch +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -#SBATCH -J SPARC_testsuite -#SBATCH -A gts-phanish6 -#SBATCH -qembers -#SBATCH --ntasks=8 -#SBATCH --mem-per-cpu=16G -#SBATCH -o ./Reports/Report-%j.out -#SBATCH -t2:00:00 -cd $SLURM_SUBMIT_DIR - - -module load intel-oneapi-compilers -module load intel-oneapi-mkl -module load intel-oneapi-mpi - -echo $PWD -mpirun ../../../lib/sparc -name Al18Si18_NPTNP -log_summary > Al18Si18_NPTNP.log - diff --git a/tests/SPARC_testing_script.py b/tests/SPARC_testing_script.py index bb5a4f12..cf3048bf 100644 --- a/tests/SPARC_testing_script.py +++ b/tests/SPARC_testing_script.py @@ -13,7 +13,7 @@ # Other parameters to run the test (can be changed by the user) nprocs_tests = 12 # In default tests are run with 24 processors per node -nnodes_tests = 3 # In default tests are run with 1 node +nnodes_tests = 4 # In default tests are run with 1 node npbs = 10 # By default (number of script files the tests are distributed to) launch_cluster_extension = ".sbatch" # extension of the file used to launch the jobs on the cluster by default it is .sbatch command_launch_extension = "sbatch" # Command to launch the script to ask for resources on the cluster (example: qsub launch.pbs) From 9beb28518413f805d784af96daee917f751bd5a0 Mon Sep 17 00:00:00 2001 From: ShubhangKrishnakantTrivedi875 Date: Mon, 6 Apr 2026 19:01:37 -0400 Subject: [PATCH 86/87] Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility Update_NPT_NP_dynamics_and_add_NPH_full_cell_flexibility --- doc/Manual.pdf | Bin 902963 -> 932083 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/Manual.pdf b/doc/Manual.pdf index b11c66e12ff13315acc9093e7d55dba4c89dfc35..cbb8b0e38cff9acf2544cb14d8dda7d369528915 100644 GIT binary patch delta 391966 zcmcF~1yEeu)@I}G76^gHg1fuBI|O%vYj7HO4IbRx-7QFPcXxM(z>s_Id;go7zourY zX8NnHUgxWAz4t!r?Dci8+9>wxOAZj3f`}L`BONO|S?7JuD?BG7GmrsjYiI$_!vmz3 z`D$Zg;PBPm#2CoE(b-e+U&IClebpGc%Bn58lMa_)p8g|9HiEYe2krnv_V`>Xz;ox{5n-Y*-$=25Cy*t*wuaw`%2V`bvdhb)g!Q|WD z{jvNrTX^ja%;5Z0TMdF=s?~2I>;O>tacW3;(>8BVIgrY zC;`&s%|xKYnbD&yX^h4^4wJ_m!1RylMhw#ik5$J+2xAay#|nE5aG#nFLu=px8&Vc` zgQq}Ii@NRN0T%F^XO7ZywBxa>V*>kO7(Gni#NC4=vPQp5Zn-hb8Y(WZpwGaUw@GQO*7 zk>`$gthE$5O2P6{j?W)@LfBU zci3ip6Rvbl`jw-kNvD*f1VumbTKsznMWR54^ikuI)=p@YdqEUc|Gm^elS|1LYO%BW z5mus)Ji_)P1J$cbm4H@I9BwK=&Pl=ehE`m~#VX9Kj>y|$Wl9?zEWG@EWc4m>?UwaoY; zok~!QU+W6qQZ!l~(E)F@j_~8g!|(1Jw&WB!CVp|`A>+P2Z1Clm*TTu9>mY@S2PpEU2&O%XvVHB2b0;<&M!glpWcbK z@0U&6H&L`zmV*>xIFGD(DGBp0c;6sOoxPD(hmRb+kq$Qpx!>)cBWZ7>U)60xl|&{t zRJMz(PK?8ga?%@v)ZR#l?U$i?5cJf953HmEN=Nc>`u=*tQ~0`@^D)rKo%{0w2J0x^ zNKVL}`||+Ym#ul!Okqo_7rgHq8#vxb+`p!nI)fH&qD}BQgqF?Y< zR*>!`2Oa27Y)KROt}Pd`3C==ep?U31owt8|EPE%|-dbN8P=j}8G8;y{rFZWgF5=!h zrZIWbl!|DE?hJ}(@9Q+1rI)CUf(j9-t%4eWqY6wTa`qyJ7m<-N@US z*a#XqeYLd#GO{ys)(T4{;(#+T#7)XzA~7&9FthT#`v)Ks16!Q048~s!+dmBZzZv#_ z7><849RDz!|7JM zbPcINjhor9F-eYJHYN~G@F!Y@6*+2tP}Gz4>h4d0K;w2UWSUVYvlaPlO%I~dO1+zH zr_8;(OFK18L!WKq5gh7=aOshhh(3Si=pdur=%vx2TC&yG5^vI z+2b5qft1E2Vg9b{o3=pZR;PrEKqWx)RTRsQcKtKf_t@Dk7CXAM+OUF!u*fh4*Bf41 zYbkTPv_Vc&DVEA@w2DRDrmdYewwDa!oB!4*f9vEOcD z;)mw`De(>HYJh<9_#1KF<|%cZ9#j~na!V4F$)|Iq9+Vyt-#NexjU#$}Mb*E6e_UY{ zVK982Ifs~YCv`a<)}T^9dBxB&#pkp-@h!eW`ZTOUdh|Z$SpLoR*?_BfcuO3|$FM8d zr_W;S#}VDn6#=+-H)o~HITIRIqe}T>cX!sLSZq6jFJp$B7S)G-6ZSd-*`V##C~htRr{;4Gyy`0mfTF{~}gOe}WZ|xf8T-c%d=7i2Mp1n&% z%(0O_ND+QO78am?V7Ilbwz$1td|_9`LQo&yyB76QFT*W^*pI-ZBps!ISg@QS>pzYl zjZMF!Q2rLTzqr%*xYfBoT?=x-nReryQ=&7U5iG)C!H^=C;sUZ4l+_+mYMd8w`GHdH z1ltb`KV}?AhRy~-xht6}vO~Fj3Lh{+qP{fbptW>d-!+ah%O)-Ha(T0T zq67Ao8yUGhQ5NbXK?O8}yzE=X3pfo`} z^y#Ptt-|s5@5#8ESag2`Z~A6 zO%77;oxR+C&zEp%jofS<=>#(M;C(Dbd2;_|?^g0FW*{V#59AR&FB?qTsEr)!>1H*; z1r+BDm*o^8^CsdLWs{d3rk+Sy2OMi_wOKkU7&xx|S75!~Bd{j}I3Fo6NsJ z%Z+c}C9WJ(*j2^}akIN78xdJ-_3`y3#>jfkAyMjc*Q>;7Kn#q7p9z~sq+0+|A}KuG z!0PUvkAoB_svKg3P?~dN_|j%-@|1PH!C_dFGjd#k0py0VsZUwb>l(nL-`@;of_$gw zz;^DdqQr;(mNGMbI&OhH4!#cGj#*FurSygkpWd0lk>g3Dt_C%iiw8bxw+r5Qg&ed5G z2gSOoJ832iK{EV>pV+g;N>Lp?>r5Da0aWa0@3!iPic&h0$N}#g`wcE@XEcjQ~(6LUZE0ywCKp9)lAo&I^JI8@bLFh0KTSH%D5uX{;X_>u7M|1N^&BMf`r7FkjL6eI zzH8;uHC!Pqcknfs%Yfo^PQB|DCMr%FEe?wg8G%M zE89f`QUuB$HY5ZZE0WQIPQyXgaLx0c?{O`)t=5#lZEPfsZGYtTS?jI-ZVlECl!ZpR z^Fb&OSOgvb_xSSABvXG$=Z8yd)g~;karqcK$|*e^qAjjc6$K^%C6pQXMWlgbXQW6; zge|!Z25q1gU4j@DKd}U=Ib?ryfFqltO2}0P+JPf8mVhiI>#DdwVFi{N3?rD-Ub#9O zh3K=Zlu1038V_N5=&awDAP(>ZQYm<}88T}jB{NN$i6m6V04X@KXmL}?#~245 zX6*C;*wHEApc_vo0wp{p5kqyhFkYwih5ABcKujAPpbr{EB`V7YaF2z+nw2AxCtF`7!CC!z@& z_rbUzv2WP?LK+SOH5xtSUy(FtCk?g3_tt=Yq$lZI=37Cvli!>NVY0vK2Y>udVAIz2 zdg!mXIG*XfB4o22J;mOj+D`QG!ojO}xAhbIowv8Gm&r=|DG3soJSMcB_fofXU!?!} zL(L*>;QIN|uYSpIXP}3=waQn|mGBn{*y55W3<&m{5^&QXA$JU_qScUGz9cv?J`G@?yFw-nO3HyqrIT3n zrN_=c0^cbje;heWD(sA6YI=yJ{&tK558*mvPshRo-4yp%A58f9aLhF20ZA zaNAJ%X>BgJU&Qggn0esxM)aEe>dtvE|Kc{6b^76XmX-~*}7Y-@Q2tE*I zW?EVlIwzc36b8hFXW0imsdKyKf3!V{?mv00P6oq0x72_VtIw4e#FFfh7aVnoGKlCr z6gh|-XCCzn$x=gR2!-&vsgz*__Zw&cR&pe5D@5#RYb@5NZ&->XJ#zfpD)7)f+f&%+ zrG6;V=-O7*)~Uj4fj5ju)JU9Fb8tq?2(oBKymjZ0#Rgc;!BOiYQ&}Se8(cz zSUz)5=mrr_vM{+OTS~jGao46G|>QD2rQuHDQN0 z9J-eIbS%0yw#7a|7AL0k1tjJt?242Xrq7DFG{xPLel1HK%~K0XIyJTm&0IBhQI7d- zJ$0rKy!-`(@r-XfK!@+tvikd|>KYUGYu#`>n{?W-N}52k{j6 z7S6BY7j?+e@`FxoT>=MAl`n&9xDMsjRk)vqe_f=2T*q6VP2GFX&pYJ_xN+?D$c-+$ zem{KQ^}qK>&G_^b)%Gm9<;HW6I|!3c;F1mFeDggv-wfb@UqjPEMe7Gf2uilddA+ zom^D}iodEluRr?bCdG6+{%TD-p4_qvzm7){|JTuf^OWESIy1x)wElyTm z-gVX5o2%*kHQ#K;-Z3c?*O*S%?OTr1<56w*p4ogy;hEdyReSf&@!YvQO^5Zf_r+~6 z=(v<+$GnHihFSC3;ybG9z|jP9%h)~(SA@>E{ao4VcwF0}M+VC2{*jj;#`y9*xQkfT zo2XLCL05RT^pijRS5~WF-O;JIoQv+2_}&Fidpz`$GA3TJ$d3auC3{<4Vg-qWU4j*C zAAiYakEQ>VFFyNDB9ot?M=Mv(w@fUW3+m=26))XnDwimX?aXPDG`jngs2dk77AH8J zAe^LFD}Xvyc`TTRkjf_ieE{2f9-r{rso#-L`4Y+( zKTaptpdJoq?Lv|!CwMjD#zP+0;QhJX{Lsxw=WU6NSz1i_t?6`Sx!w8gzI=p(W)P<_ z+z}S^4(#Em=pMrH^=GW`gVx>n@FN^G_3*>-`kBy=7s#wqADU$K5?Ls;zb@J^+(!We zw{s7__cuG<{Mrcn8EkBik|4f|_-MC%6?BHI3?C#4HqDJlC^klgcS$yS&f+kxsl-H8 zqPu8vQ)QyMm~3k<+qdBL6j@?FIRt85?MGQB(ZKNj67eGxhCHxEvKlfn=vNzjdjVx9 zQEg&zFiC2|S9@S^)S)M4V+AgVsWT%*yrQZ@(>}7vchR#Hb1V&{F*dPcBsMwN_E20? z{rKWh78(dBFDMQqFRVxr4TT(AF%<0k*`w4o(K9tQJ=s50LpssDPzUFiOz&oMH&FPGknL1x(>pNEsEp>d_H|&hE+UG}h zfzMNgv>qoo>ll8Y0?b>5@Y_I~&qAMuNQ3UUc$9FF95I>jQCx1mr7i7iU~{yuUnx1ykM$nQcKzP2V1#shKIqK%0YDWUPd-$?vTxreRmDF-^hNZi zg8xo0_yJMsS3nQN$I0WtDM4fMDis4-o0`okSxT@JlwVTQx(fkCmerqKcD@x@%g@%j z%-{1o;u1lI+xFDKz*yxTz*eluP2;xJq;^n?tRy#clXj()ljpgkh}#Yhp`CRoT*kfp z&Ia2Lgb^yG4?zi1)l0%l8gJgb+2wy*hBx<2$E1bx#v1nFq%!Fda%WjEL0Ft@(U-f* zEp;UbGcQ&F8#(}Oc%qdYv~a;49jN-Tj4~E0x-A)X*K!|5&6bx~aoyo7=0?XB%o~Ql zZO$1*G*g%iVqW804&hT<8~#H7xMetu=fSvO?|9i}wF@)I#Hk=heG-G%LhKF!XZlIs$m zDoNJdtWHUKG(Ves$IA;cd6zP6hscJ1$PAL7J2&UXtf2DLl01^V`Wl8=9rcXGw?9TF zDB&GtoJoP)BwZ^!mA>614E<`a=qMXa z@Q|4eb)K31 zto#~ZXl?51Td89@-6!xoqJBz*Y_?+?#GL^Lvg_DUZQQ;5+YpIXH%l+GN2XEV+b-j8%1oO_zp8!^pSA`BNN- zG0GK?6+BPld3QpVOL%8NWQpe2naHvz?Q_XccjI)qo2vqjmju ztYbx*i22zO#PI|qwjC%Agm8OCARruRb-FyvZX;aE6wg?VRjtG$WbZb$H~)$B`>EaIXwmr{mLPnv?%W5#;upbBHWmjrtTm%a&37K zcb>lao^G0mO9r!I#VlPBz?DJy$hgE>>SXrA?AxKQ(0XmY`Vquj|1EVYFbW1_* z<#&Zq`?NUUBHJz6?aa>x8W84n+d92BKf#456pn~2>EiqnUsRkYmR{Dpm-Ej)&Z*&) zzVDN`r{%@bx^uYG^>m3Stkiw1699P`#|{d3N&ElQFdD8u6?Tw!NtHRn>fE#gald?} zf(~@v%n~?vMl1L%D2Byupm5V7lShG(I%-^`l3Bh}G#O%zY5oMsCsikzh>FEkuN{HM z>+Z&l1m~4WLmT>Q2AS*oOukO4gxLB?!2pATIfK5;qSFV)!T_XX26n8-6iHmCQB4V1 z>oQGA`Nsv@&+WLIBVzqA8y$foAeQ0O^b?ilH?^A7qj3#Fqqu@YESZi%@kVI-fyEy%!bFNj zYKBCLr-n*@7WLEVp%$8+SjJ?rrM8etrZ+fQbKfqc9xJiPV5U#8>{+!lfmjLyVNAZ- zP_D(~noPBm$y?euYWd#PjkkZQYb5Sa&NGs7ZHgP?IgUkNJ-i}sJ+RSv)pf&AUYAag z-Bac-vf*mKnLd+kTziSgH!C1j%xzo{s*ua16Dk+v?{JL!3{guEhwUGDYHA(iv|i4I zxDC^A$izgrKW$Vuh&^Q{1FA%2*2nLx`84ozh2C<|*xoD{P5EhCr(b59|BTJRG<$}@ zq+un;s6UO!P=Ac4dV0YxP;`9dd*9UDQW#n9{MrwbEuUH>>S22qEwy1QTkg3Cc#y|j zD76PZTkXxc^NN+5S?Ba##6WNwyZnpm&%nrpt7Pib*+f_N2ANolGmuprx4gTR!7TS_ zbKlTi#C)R6y5pMGXOy&i12bOTone~24RvvgFWh-EKTI)OZ&nLU;C zw1TMl<;mval6PT3d(QQX{q~y+)f+Zdr1DF{3D?(`#T@9u$8!(`ZXtrzB>OmORekLk z=HOi|KZ)IbmSf^ZqR73K;BxJn8B{Ix?{T=b<`!~s^Wm;FZKCDY=j(u)B$RZVmg_r- z4hHVoYH$PYy9c4o+8pw*fOD#J8f=4kejQ>%GnWFDowD_2rr1`P@uct?a%|O*rF7a- zOkOQbRWkScqd<@aY-z@=%mYiKR?0C)F$M-8jqd_Z8mjHD1SE!*i#1 zE+F$|Z=1)$g#`i1pIHX!LJFxGks%41n4r=~m7 zlBhf2L^!a`0$abJq-)Khhe3Sz1E}y2*$gon@DP>Ogx?EUt3FvMaNguw z3Q*|-{-9dFs|7G|vxMCK1s94PumZ4y2$@AP-?&M{b-%qy#=k*@!~$Re`LJ9iONn?v z&FZ@`_&>o=VFd66ZtMY0Xwc-S@1eInc%^jYu!H;XnoXCt9ITKeYCNQ%Bx-d$q_r#H z_~uPoG6rsf{|_!FI#-^fH{ZM|;Gw|*;6OQWhP4l5gO_ZtaexbDBn$z-AA|@2Y$|3? z7A^oM*5sW`V5Nm`VH`e2*q|w&80Y|&jdebxBIY@c_DN2LiRD*n@+zW-N(rbFUU(Zo z6W9jy%jv3*^;6^Bl!b&m%kJ4@AJRjqpD!9BDI^gQEL?Y|mk@*0h+QsmmjzSXZKt%~ z&u=eStiC&8`fxsEfJA@>_}@ks|0KH44Dio1+3R;{K$J&;POZU>p|Vefm&qF%^xnLK zXB3*k8c%kldy_laAbpMm24MvFHqJ9qP?x18V)cXShY9h5b?0RL|Q`af#M2Sf_Z zaEMYN>mn81>F{U$-d9i#%SRvJ2L=lb{P1ot{1<#aFzP#v+ST5T)*l@Q3D>0cV`FUk z68Zwytl^=tAbA12KsH{VDnJi7ECMKmho;MG3~lGhAKvFbfSL>MBMSTPnfm~E#|10& z3l?*fp?-y6vL)&s-plehYY{)`_~Gfx{1_XeHQ^Fp-EWY<^4kgI-bxjrTGkuWxVdl@ z2NK*jwG@Kf{z#+Gs*d*hB+A1m8$k8c$ejX(eURK%p^D2dv;w8^O6)?lOzYU3$qj<< zxwCdDYI)OxdWvg#jL*o@mA`~@e`OsGWe*o=0;7zkJhQBN%KH3k^(P&is|;qTVC@#l zZh=#QvZ>_1jKUi%qflDE2|9PFox;#|<8$!{8>DenOrvRYK~cvpI}x=H}~ z)tlpU_$dg5#0)F);rpHoUh_T;B`%g~Y*yvCHIHA=%4L`A7W8FaA>G<^+&Ec8eSlQ(|ju_zqC%!PP`3U|Lz474t z%?-XD9-14OXrdqJTQ{Tb8XA$soETW{rW_lYsVZUU+tyFuo#@jt;P08Aa$;;6>s+x+ zExK>=uJwt;SpLRHwLT!n(7Z4| zM%}nFUQt)Dv~E*fPuHbu*TgunX1ND)i19j{PUO7{KZol^7OK-BLS9Sr%0@Op7xwr> zP#h7&36C2U%J#U3HYHeC^CLl6F8Yf)NqS(=d`?=s z*&6;gI*+Hbkn3C&*fr5)WXGAl;BexleC_Xh$;02Nydp}g&>YK3qcOD7EZtB+;%&!M z24|4$o0zZLHhgY9p*FkqTjVQ=OL^Z{0>yW}uX>$P7c?dDEAt(8+<>JX5eXH#4fQ5T zvybKqp}Qe(6o$l#1{GGu$rhN2#`NNj4+QJfw23J3)UZfWkgoevO#E*|-EoEV|_ytUy1`4YZMit-JY6!&%Hh#iu3c*|+# zcO(dMnsf{YUl0ElQ4XVidAS;*{!L|BTKbZ>d{pvVR2f(1%}L&r2X-M?ts?V|KD%fHC*7Kmb%&yw_EdbtvsCk36o6j4qu5>O|kkY;
MgIlw-{{qRw~13H`p=-mtSe)v=emYNx?Zh z8oTKkGMt_1FKd#45nHZKiqOsa}b@Izrn#4{KywT`GXKy6d=t%{t8I*-!}8FR@@Q0gc}VG*brBP zLUWhx-W~j@^#@VZcgN(FWBJTr3_!#M2t#+pfH63r{`I&7y*~>6pxO{{Dn^xs_1Dwe zhXM+)1qguvBKvT>8~^E|b9w>Ic#Gq_K?X`_`e6SBLu0TiNC3qDH9-IORsN~*`uKsN zWv@y0Epdb#o1yUsV&z)0W&kso58xd>3qC&bwq^DQ(=ji3=~-!(iUVAuV5Eqd^}!WG+X?HP0lH{q(r9~`zFu2-XwZq@XIm5+q3P`oeHmqi`RHuCYn&y!)F-} zyDqk{sEwmjmh^7w*27kzpOGo8!r*C(?m{K^b~iy~_?u@4Sp2`%3GwW7U4eB^eh>N@ zS0Hi7wQs_eUu>FlP%+pXSiVy=K*$0ICu8eKenfzhzm-8zf8}2DPcKVH?H671{du9} zq(2Qs$$in6qw*<0O!7!BPdcaogS$dtIW$u}=a{st*yc#cVCJxOCb=HBCF<&!`CI)k zE~9fU%V=`zEKQk4OSJn!^|!`gPU|zlzNYHiqI?hQL(VTJ18dW3AL{CHX0e7QOW8W2 zYwr(0FM<_oclEu?PZP=JXME0k92p(vuOe$5$jz7?-gTz$Q`;i??l|fOG`nA;s(7-& zoMf^ueB9lO2L+t$^A7~Xjmj5*Ev34i3SMoRh79hnB|G{9UzYEP&}D*WVxS$PZzdRD z!BVp2n$Z>w&_@}Y4UobmA2*E%T(E+;d(S}UABaLzl<_Ae^j0_>%3L+y_1??HijSl^ z^zpXl5uIwy_ExXuN0DRoD6Qg*dFCfYpAk})%p(8^Pv%KH>HV@1*tvVMveIhhsf-yX zOYE&Z%})Ic)om?CKXCorjTp&to{V&4ze6`NtTHue{lI_^YBa=-kFarWS7Id~CsPHn z0yX>QSt`eW!3i!k)eO zGSl?6T-v^7B{%P;+nUQSLj{l*gh8-OafpSFHptXg{&ODCsbv-L-Az{KOFCIMFN~&zsE|ee?N#myfH% zmEm0R?YMV8sc10gI_XAp8$J;o3Iibt8dE8ZK>2GS7XMu15RF^ffpf#nWmiXAjY&yU z&y~sVk*ToVpHo9ayS{r%CFCl+x3ls$*Z|BiP>KgHP1nJm_iQwU%dy=GB4B6d$g3>_ZIAS@u;?8WEw5_S(d%fmC-Dg}!_6 zX78Y;C`m`&W4hQGr?ixq=qz<>1VKX?)yHe3^5PGz@|}vTbYI*WmmfAgAT4|3!xfn? zH}VwNDHF3M8B)}<=UH~yjpvwd?Tn|{Xpwg&7}KM-=2*Ao_dxT^*MnGd?9>%#>

4 z2|X#-D8slvJVq$+QgHZH+1N5c(X7>|S+gwl7dtbowG^>kDOxl|$r>8)AHHaOapzjn z&`gBn($Jz4Xb zEicl({&Gvkt`g~cLsUw7*;a#cf%G;-OX6ESpOjUhvKSARW3dtXak zUVPW6WmS$)g@bQ{Sa<)U8Q)m%sm>(&_m+oHl|QPrdWb)}nO>1_%FhYiU~#HkgD9b( z?aipQDCKATVerCxZoaS|k#^`(8T=bN>8(x^#bu_uG1H*jxmgLb?9F-#v-1@8;Pl~) z4(_d&0|-ACw1QrI=gZBUkZ+Vpd7OJSc~XSiR8~LnkB_#0V()(;_=$Gj;*`wYEz1%3 z)|4urVV9%jR{j9jn9o*B>avN}ywk3^f$(DM=_~t#eZGVr3rRyJ00tZtfcmoS3!o9I zg6$?IwFw8IdV*a*{huA1UhyH!Bdy<0lYW1WH~`dqfB-(g9`F3PSE^$;x4rORM><86I#ds zhzb2#!GOvGxBzrP0MSwOB{HU$abNiVDpheROo!^=8-qZ4q`k3kFHD34`yNUQq0{DA?|3FyUH7q58BxHfANF!H6=y2s;ZotD+@1K)!pT&@L5$UBUx5enEi?wH65=>_v|BbCl8%l zy8g59*7si0mqFdET|vrb&w;%A-V$+@q}XLS{A+0-?Y^suT#do-7OTZ=D6T zk?aDT<~@#hU%_`#m*8*JN?;`saDxXa4WI$rYJgPfLI?a~>iYjJZT+-{;{p4_RY8U< zqZj?lTtZiX`ZxRVj|lds3ygoa+ofCudhZM%?UPLF`__92dHMG$zwLjxu)T!*Xzpxf zivfi6X+W{gTv+1UfdCQ$9(_73`2bG{V9>ujD*FQgfAEtM@bA5f3iF>MLnVP8w8eyJ zhyH8X|9FT$0MdcQcyt;-)`8AoNB|K42JkM}zXMAk7vh5~K7b@x*v#O7=7s%?2Jziq z4t}2l!WLLz9D@U587G~9w*ldxA$uPf00F=iAaV*85!6*=fcodl%yj$UsXz-0p`!bV zq@&7whWTd^me75O0*KzFI-e$guzx~IA6t-7R{?zrn6LuaA8e_BB`cxw2wp(GZS!`& z%~L`-_W#i)gB#>&tU(uKL)*;)c8Gif&anJF7Vu2W<#az&F0w5?#$SUgxRHUqQ!-upUtzZZlz(2kLRSzGK z{#Vc&@(ChqfZ@-+df#9GoxrR(fD^ip9QdCJ0dxcGp&>fEeXPbbe~9gH<@h-x3Q(aw z(aaFnd?Eswi6s!%bnoznaAYJ1p!;rAsn8CJ^4RkA!-@K0^%yb5^gc%1PzXXM$g>7+ ziD|$kbC8Cnh9P;uGIlFd<;GWUJswz*dM7dgPNN6VibxfeLbB+-VtnTsHuUWXNG4H{ zqHyD3k{$|<-%hDMAQdrBgccmze$SU@KGuK_Sz6nTztdLkJ2$lsVs(}=Id|L5AliM5{nCMY*9Fc6aI~5sHL!bOY0dv$+E-JNng2YOEqd?M8CeEz(izf{!WK2S}A{6GZ z9gGiqlS{5TH~|QO{RpD^O0kAKIU#eRH&r_zLIq+CBAXGa@7<#U{!INwW|UqEq#6dI zN;W_H11F)e0<+X8gB7G)i72N=B|;Gpz}g{f+oft0)s7|BjwAHr-v zzg4LX@9a~&e@iYjWp}pOJ`H0Bj30Y0J*f}J7p%YRJXI!1+Il;d&*>%N@)4xsW$S>F z47|eMbk786yfr_2)~~!q?#k*l=)A%G_6{FgueeQh_I~yrAS8_3*<~L;Jl;L-g2jx=xl@TV<>5O zJu1(|PY-&M)r_fn8LsC$KR&*f)b8Lat>mv3(tCB+Bh6V~(RyyYlX19+=6eLKD$-2K zb^eBIe`>v*OPX}k1Igb6@^c;Q5n`;~MV8wCW>?=BzAbzkU9A;ae>tMld^sw!{eAY3 zIafov_%d9&ei8|JKicm6ySsjo<26HXY43@h#Qyg*ca?o+p7&zG_Pn}(-tlpJ_Pn=q z-k6?uG3~MY%dA@F_~!N6WcWJhWw#upd{bL_|0+Ig{#H32C93XUZ2X?iuzrV!Z8Vp60of+*TA`aENz!Zw6oUVTevMk$UnFs_ACEv{5^fju!^ zySmkj7qB>whgr-%5Vl~FYkvSiYDH>wFrS&p@9Awr^GR4dmp2BqzugH1(1zFr{qu)- zG6_wRh|p<7BhiSZ3Csrg-F6XCi|=m*4hACz)+dx}SG<^*M3nQh5t^%bywR_aIMKT~ zIwq(7GYX&vvr&{Xm$e%Xi!qmSjw*2F!a#&&^q~&UO(Qm5@kt^uBcX*5v~Ln{+{19( z;_%!ifstQ14FaKuBUMS1kQpp0_P1ORhJzwadI~7&5HP*c#BnlNS&J3Fk{EOV3^*)) zq{V~xZtS^S@OHGzl||E=g@%y-ihfjgQ0gTF`eA_j8Yo1~dveq*E=tsvO&W^loO|NY zFP(|4({@opo$S@Hd7Cs~>JAfzGs{Y-uMTE4V`(*?lXv}3NwxNbe}1Fr^%1u{;DXI} z^zTWrM_XUYL8#br&|1anKCOJajbm#UImfD+$=&F+s;H5jR9SR5xO~koziLolgCg24 zCGG@`AMtWo&n*w!_cm(;e`PUAxNW%pS)6<#oE~G*qGj$M(4+Fqw|bj|(kg>l+kT#~ zY<)c?+c?(Zs;QvcB8V|{kDmx!;afGBb2dY1je~a1q&`)aox3e4_O@ZS{E-#1oV)mG z07CGi)os&?Wc?xg29n-qGS24eYm--n%FHCIkchS6aVD@}jJ21kWe`bz@L)Je`bl6?5P!Bd z5f%8CxDyNHBqTNn^}m@w2->)dEIKfzBrxyyL{^S$`J_p7FuFfnoJ$N+(i$QdVjS?N z0{DA%MO*MM;G9fx_S-l~0znW6aRPZ1NmbWyq)C%F5OhiOAHh-LRC5R8&Qp<+bWy+% z{#D35DeVT1Hf}$UH!dv`Dd}VZ3>$)#mHF?~S)=@qAT4X#WiiCp4!!Q^(_qPa?}2QJ z2{vhV{e!SPh!&*24X!U+w6RR$Hm#t}U~;XL*)ces=f;*W(2S1uJ=*(xDd-{uFwkX8Ng`sqzdyw>(%`v?_KR+w zu%@7zq_7(+4do`5G4((VeTi#!MH$-10>eb$C;as#Nu9KYZWqgkB7}(&kQ*aHQly_7 znr_Y}mV#3SV;RfG;XpNv&cj(A=m?wTxrhEs6OPxd<-}do)`g z7WZz4A}<203)xCE8k3@g)V+&6=Qc$;=L6T6jH18{oS0;oDEM5w)80VPhFJ{^v`>qj z0q8+x=&1)#=67M_nxLA)*;{TkK#%4@>%q`F`?G|mEFS&Mpj#QY2o`-L9%n*RlPHiJ zfg7t2O2a^c@h3Q3bzLk(46iizm}g&bE}T$JOiHCsuBL!VZ10D~5LUW=s6|;Vd)HXf zR$l{Z0&2exrnj@X;wpSZ&1aMTIJquy+aN{muNJ>!hJ>jy*(>qfUy_FkM{kOLOjU9e zUR?(bnVDmHzY?CF7kLWq3bNWTZoq?8+6ho$ViVhK0@w;Zjjc6+GSyXH8H(TXu2c&$ zXPl=EGigR^_v%szGNSvj`~YRy2R=i#{B`3f%ZjPbhVzZ;})9-I#5)Q zZk=BQZDJP+W5FKnSTMzIqWPo4Ov7wlB5%vs)ovXwp<0g8qk}Esl^Wp}#qHZ@+c#9z z>pL@tZ+i%L<941j^crK%OArv-Ex47SS17v>B(z|7r0V0vL(1ec{R*{J<70$S=;1gR z=Jn8&Ug&~lhcjL_$M|Zez!Y|-6Of7aG&I}7JJ&FORoyn{?&2wd(^_FPXuV%y;I!~i z=zs3P9np8EGw&bQ!24D}v)&2PON(5pr2ijGeRWtB&-?c09J*UTy1N^ckPazDI+X5^ zt|KTSNFQNUx&);|LQ+CXK$MUUK@bG#j&}~|`}_WLuHBty=b2}Auls&tW)Hjlx7D2M zx4Sqx>!f%XX67inu{Wz$$%*MQ67=sU@M8F5;YZ!bFL##y#7=r4Ml-VhTPrUk-7cR0 z^)JtWnQDV+ZIE7FLUdN_w}|Z>PG5WNfW++)%|_quBD7+S5R6usX?SSsizcUk-o`wi ziRW5Ur{5@+?LG;wu)535f6dD#)(3-SeAi6r@cV@p^$K$`hj%vxx@^9gclMXUm*QWR zG-Kx)>VH_!l6NgdG7#`xvi4 z9Q0wHJ(d30_hTSHvL#j~VUlrr)_3D(oP(cpAA#@_pXE|DR>q8&IQBhH=u5^IT&E?A zJvZS}!VI}&H>!=CDpMxL@8L`R|GoSzW}mChr`WmV#%MmGx^hnE=qA>ZgFxK#>#6*` zU;S$2RSEyg*aHc~R#8{Kp4ec70Yo6+Z@V@b?>hf7S+DJS43)vPQlWy*!Cixse2Z5Z7XKea4z zI5GYZ+L-#Q@AYhSX`ck~y4p-O->kxD^WNE->)N-oyP=9V5gKpbHyZyo#pIi=^{74f zkEFddM*QLF7qKU$n%NzUFM_w@euyhV!31pw^XkpGB**udj{-mDbUKv0SyEiNekGi& zNO>!22W*}GfG^B5W`7U!)kw~YDjs!KRY+g%(q(5%-UQie(YoPDF-^_wUm`yD?!BVW zQ1v~7%ygwI*Pg4t0ADrutCz{!oZ`cx%-Yt*ElAmJ>EttRK1F-H>KkRF@ov zyz@~2DPJpqq|c^;Jka1;$g&nez*GXr#cWEXScxu@wapCqHisGzmOgU1%@j$O#|U{~ zqM;*Y%Q=$T*r2vdI6qS0fEZ~|)(PEjfKx%6ZD=@1net#{Q9B>9e4ZW&uV6%`7TF+Y zKJi`ZGA*`4-snUTBG6kxjcl&eMV54#A?Hh+knY`P$bwQPWY>EhBykTL@}!3kVibiD zA*ZW*ku>Fupdkb)+H=)$d<_$lrNSC%{~6V>Ao53rEwZ!sifQvIuOl_`DNAatJ}H~@1k<4A!925=eGdzd{MKk~~V9Wv`96H>hK0k}jm25#JKw1Z0tUJbRT zi3VxbjxvHo?ym&>mAzQ9GPAHe|F#^A9pq*>slE>BM(ydP!~-I zNWikLjN$5HM7DmkM)~8H&I_Uq=mW=p-4^7n_Up){Zj{b!rN26{Ivm02(E6qI0?7Uj zM&xSWrD@PdG#DRL9swhUK3l>FkVJhANQFsFtpBCZj&QeR#HG6Pp)Ar;kbL5~rv3$xsB1uzy!|f3$hd50}!ZRolt&5U%w)tXy zLu14Id0I-UBHrQes_qa*L>e`reH~AFHKoQ%-s3O#9x~x-bVRTgM{y>Q@=NnOkZ8@p zqo|G^2;bs4M|R_uG%b_zi}efLEzvP+Gq+g&w8?=uoKka=9_ry#=-n~S#Yp^l4_S znMA^#ADm8c?a<7tO@GnTNT673iiW?2KYmK(J{pmraW@wxy9e=$-Z9wMUoSOT(;VZd z=UpDABPa&QY8TQxVnx#^`E7CP85?nrT*&KU*cOvE*#(mg+Zv|I#@bF=?U~pas19DeURPK7_h_n^pwB5O)fHN0j){j2g3;Z|4KU z-fcdT7r6RAncePw`kDIW@pkR>bXDoX zm|Skco^m$NCT}|=n$h2FdCd$`yyQ{u(UqqHQljc^;wcOe2Quhfs;t-mM9y+~$ zz}S3l62nhVKRbOhy5#}?&fsi^LwL0Jy1*))kV%wY$iY4iN0QcS9CfF@J4zAK8pcL!TGC?#ii9~eg>7J>cTJF@ z#0Z>w)Wk8jj*F{Ox&wOnD;S1cK4gydIWi^H3Kx=*p1ygaaG>A11Dh4sRP>kp)O()>$|BR-WY zCP}SCD|oSbzqxPzz__x2J6%B0uEC#}{4{*9|s>yJ+~x^pe7kah-z< zV%NMR+`jnT=!s&Mef+1VdSc^KgOllMPpl{h7d1K$)1JZf@NawQ$1SG!>>H_3KdVL4 z4$yfYZD!l=3^yoebNHzrlM#j6zLgB!z!ME?=T-j7-9sDfr<-A=TFP7Qd2mP|8h!n^4>x7wuslU*ds@ zG-F?pmJWTK7}hJdH?Ou_O$J<4>P7Bf8>6JOzGt%KHTGtS&HzfGyib6H7!p5>0q-rCF61Xj%aSzQXYc>OlBauD-5tvc?_xA(>j zPgI;DYA`5&N%FgA$HWP5hktv%>J(h1bS(9X02$mCR5TpHGt`Pm@2fH+`1lQjhcAKM z=J%;fHqlqN5M#o;*rzF{QJfxL$;TvNn6LoEO@;r&xTYOrO^)r~u`Jv2w!XV(a1(K7 zKzT-eUHiJ|Xy0kxyE06HuA&}^wYC>^Vh_hYR}X~2N$T6jpN3YM^;ZlJ_iZWv!VF!O zH7$2T=A*k*Ol^$rrH1*MmsQ3Mh?I62j<{vH8l|qQ@0<%3^a&zD>kKe!X8Fs+ z5&6<1*A-&@=$InOH72vM%P=RN3&k>v8IM%S3VnRi?QCLdn``db+DJ=16#g*HvUVCwXuOhOJ=2MZ!1`4jl^%6;wBy) zj=ZyYHI-41yQ4{Dpx2d`n8uj6iq)wj-1|+^o~>nO1jZK0TUzjf3fuGh1M@~QHxeJZ z2&F@Ba*da`nH0p8agVrW;ncU2ir0zmHY50EjcQ!k4Nv&7)9$w3`rh@7d!}B=#biCw z|9r9;|LfO}h7T6<&;7scS>Brzf}bqdFG=4Ys#2{d=?)*lu<08!xM^QckbV2x%RBnQ z`YH6k2A@pakZqiv@zl)i_fGk9biO}*Hs65Xa3+h;qMwnw;f81odEQXqCpX*DRJ2Tq z2&O8Q+fqcMB5C>dJ%stu#iG$c6#W|_xv3e3ZQ_U07H8Yue*Tfi-+n~OY#mG<$W3p} zk4Lso7Mw&XKF&G}{1ta$EO=c1Qq~Q8Ab{w#k)1SN9i64D%c0sioi>#aktm&JeVhIf7T>Yo?Y>ul(UPB0rW{+# z+E!twv^t^CA3eN(vwYRUZ0z}3pr`r8L22L4n8qokw>fqVoNoHgqQHAvXZ20UcH%X{ zFuX-@XW_#?*~||~t+S7F1(rYDkSVgZSsFLaFMYZa-%>O-GIuxk{Mqkax1ROEgW2gy zLGO7U`=r^V1aXY{#81qd$kEWB&9nA>j{6=C7+J}rpG>FeYp;ntEXEivM8?Gimm*ac zU*B|EtyPwrm_FOyeG5-2-~YkO8Px0LFcy<4G3#M6D4>GQA{O9zxOskaf_l!RJ+&V!6I9_>N@d^paOBCeBFQ^F&#B5Xo=CjDp3PpT#GK_+M0UGyJ=?|$m$i~) zS>)}54zPkQ_KAr?fIX{9%~GeDTWo-Po}KuD-ncUpBI3<0yC8arO5GIIrKt()9RtpG z%3OUDo)HJ^7ukfX*J=tLRNo@zd|955U9RwAoh#goHvpDoSeGZIiv8ov%<`R=@oJN>gpt=59<1@R}7Zf(TqG+C!#^0YOM3LWbKu~|pV|PL__2;Is%Di%~=u7yS ztM3sen#rRqPx7PzgZ6dw@#w8E(UEJ#aL4Po1h)!EcD*$eGfDZHNBUVGI>WwJYdAw8 zuS53<-Jd^EZsf_s@Y$Yj3bOOI3KdEGGfE~BxZhXi@w_CaK*e-!ECYA@ zuT+B>k>?22W`t-cV&Cb8Tp;+{mf|kzwIntg7b_5>Iq>V!57r{c*+CD&=Xs z-EMbGhL-kn9SN@mNkw*!rirqD5y47fp|97`gY&`3C~CUQ+ZV#Q1+g=!+V(s7;wM!* zc>Y&DCb!xy(Y_TYQZ#bwQm%9)zU&gH^qYKbW%CG_6RxX#V;osZ zXioP*+M9$ifoSZyAC`Idh;uUA4JPxlm#=uGw3G#dOuV`^oL9b#WEUwKMwZfKJt6a4 zwu$^6G5n73EkzP<={&Dg-lO+~X8BH~j}5WP2rcLu-QWVHZ$322Y~Ff}5vJ%HaRbkV z>btxz;-&s*&F|FFYMN1|_=Ak|;5tMDTX&kvGd0<&{19(6!=_LkQ>h8=~u3?!RwFu8YLucc92+WNG`IrW25HK^B+|l1meY$U1_pE zcZCoI@lpgsH&y>@X+M*mr`FDRXcotHqo+qP4Q((A8lxDDV4FQymwx6$yvFFulE=xU z>{sX6mG_SB4ukwVI#U6jjJJ(tJQ+n|$2}vj8;mYWJ3nE(HqH2SO_{VG`Q_t1`ITCe z3KFiG+dLZYF~%!jxIC2c+i)4bS28Iu?r$iRiP(HBZ84HkIIET3VJJ{G{C0+4`v?&x z?MEew{&xF>Qfi|2@h_oCD$0*LlciPD*(Ma`*Q@TRKOl=A;D`vE6YB5bZiu&t@?Y}) zqKe_sDP48h=Sw&lktc2F+ks_EZu`0Cgkz@eP|XFW{#}eu!Zz+ zKnrRdL4RnF413y83D)0yko=|tny{eoRb~xiiy6s&$bG2{WX$-G{0Ae*fNj*pU{C`C zDYvT}(E1?*GHk~hV#WpiE9}}s%ecT@K-*(LmLF?EC3xU!@17InjSmhI_gRtkXB?0& zKCnQ60CodKxwy!Y(~n5ZLl)2!04)-N!C0NkA&HKxVIrtPnkjPN$R6^14>v<59@8e@ zglU88K)o5#=)?&eg29;~8BSRsRWumqRo4N;ee;$d?@4C&&pCOlF2%hx#yJe@lFV7lO&ZKzVS^2&M6Jp8i0sR?n= z0RzHtVRldo!(V$LB|Kp8A7Y?+hYmb|tRn#k7axqDcL=Tr7ZktJ{{T3tKhe-3S~6G@q)G^*`X>|u&97Wp%mB5KgTd<&!E9jSmroBOB?co9 zT7#KE!^FVsmRsP#3PRcI|Av%G0&{|i1NYJdvLXcr#8AVyAx0kX=3IK1|EIQ;3f2rw zkii&HBEg`0l#_X7`JLEogxOnCEjHJXLm? zzZSqn1)=%xFeWr%(W}%bgvJD;hrVE7p(FknezrcT>^n)2w`xrkz?u8-H2<38b7tM& zt~sNLa9cW7#H^H=vqUn6QPhKMPKTZad@GXC;?c{A7dF?7**HzvAygVT89Q7(Y6XDY_WFw`M#ym=#h)t5sO8Y>tP)!KE*qN;J z#o01BTl$!XNg=wFJ*P2I5U78!#dwfz%$1ia$$7SYZeu4w?<93hAMwKeFyNW|NYjOY zeVf$R77e|_EXuJp$pT(>EA%?6=&e94b{Xb{d6*PLzG&O=m_&6 zwh@8Qv)hYBtXmSJhC&XnXJ@9qFnD_iVn^~t2&6nO^8D7DaJ;ahbiB5e`fJbS{PpJg z;cYjS=c%1ur*45G-M{-I#|<6^9FtE!U)l?zUgc&(G`kz*Z|s$r7|%Ow`AVnuNqUkV z{)l%KX}Q*HJ|n)ny!$ic@dk48$Up{R`dNm8e357N;(4puvef2;;F{Cn;mE;0{(!S*~@NeL{BAY>Ufv8h>V99t^bNNgQGM#sh+n_@26JX9eCqYn$l>InW(K;<^fN};tYdE>V;jVc zWGb;f#E}6NEMbH1R7A3@`N_QncRC)HNFxTGyHxK*C{)=;lZTk(=xfVN4r^pn`!C)| zpVZ5y4N|V(bR8&Quq!LTPMW#RWoW#mxkP%Wu(;+0_j1j!-P%ezFXE@)eFcK4r{}uy zIkn~IaXxdOxdT#mS_pjExTUItDGlcX4xIPg0LqvjE#LtH@v zp0_FM9>MH{cO&l?31Wnp-YtR@xA?{|H|f_lq zI_5tvDgPFnZo;7|pd*mUux@k<*Q~;;Nkb){+wez=M!vq%@lWNv!BD3ID-uV|anjN* zJj2s)4_7Wz;fAE~cc&LY{Om3h0;ykR>QP-iE@YfU|*OlV)0gunBk3 zFrZC#m=-8Ip=cY5po38%Jx=t&IjDS@LPzv4YKT!44G%ivf^ni~4kiU^U^gInPc(dp ziVFZe8Y7BU|B3`cZ4Us}XK};iVWN;i8vFt3ldtt?W)KlOfckwI0OsG=0n~@`0;sRQ z0Zw0Wz#O5_o8ZWb6HrF90E`DB)_}1>)$#zhi9O+@P$oa@Gc?8ps1&pYL&~xM`vGe+ zKz9UT%#fGWKO!ZT`)gb_56l*Nq5%4|;RVX3#nH4Nm0K`Nh?@^6BTxhlTYNwnwHTl< zpo|StQ-Se9f}Uu!kc=oW%1Pj=H3%A3{HJVQ3^0nfAmFYnrN4T_gkZM7Kvc!<(oKO5 zg@C#&31AzgDp1lS4Af1aj=&yOM(C~dm2GU0qdKsyTnaV;9g6}xKtnK;rS?ygmkiJZ z7YCYPK4|7pn>fr4E_CSznnDp0fSXUf05@Oyd}ffAB+L=j3Z9=iL@ot-la#-*iWMdd z*!nUHBO`$tCVD?bhAb4QcZo+7x zR^S9c@3cVAQ#WBwkn3%5lq(BH*Qfkf2Xw3rhJER3%_xD#L?wUK8VreO0~;?N6H*0S zV^RRF#+7#nEhxb3Qbxi1mUjzSqpt?s9A`ZsjdJxMXT>Y-*M~mo{B?bVmB1ydH{dn2 z)C4{y>h%Dx7bvC5LZSKKYN!VAwThHc3&#Em1)|!y;k;J^VABHc$$J%Grr4zi3wf&o zGas6P5lEuKt{V881&C4~MuRY(beja<-9`Bt zJC#!>7})rdDf#FQ=I!2Lq6#FO!l{Km-SXLwcmD+0u|VDG^&gM>l7k8_g*I)nZ(wj%;y;bDu z^|oC~+#T3lR=Y17FcHco8X27BQ3Sm6VHM+qk6(8X!L^F#x8VHzb~0u;eXfZy`Y~Lr z!k@PM_2BOMyj;RFmF7=~^tQW)64c|);2uRbDYVAvxx_b(k;|=}A7ZE}*9fema7f$d zTED*tvSKdS>3+0UyyU>DIG{=|W$eWiDI(=1wAI~%gq{j1?ja`Z8nC%kNnxLCsECG` z{?tXLLo{J*h&++?jj*;7uS3Yg zklTo_LwfGTf2>{nL}e{St16v_@+BE!hb$V;*Ux50irGS?&-285pD2|F)aB-uPO3kg z=ItH)W*kA$@umlXOb>PDu$6IrXlhiGt}|IeA~L#3x1Q_yf}kgv(Z;k$%ey)9ENDKZCok4dU>9YdC_ zTxxv|Lc+7R2QS3&fBXJ9^vfe_w;qv&xI7c(PvK zgkAI_HiqbIPpEHoNI0#63|OCQr_XI~s=^cYMBkAm$rFu&@UEopynMt#)-C=GTMewd zTU~nws{_F+2s2Bz*)=ngH|3*8GEcM;L**k*C@BlyDgQ?%#ld=riIM$%9#S62*HQ5?`U8Mw_jCX;C1ApIp-&G0%=PO6 za4RzgxO>+Iz&BtbI!N6F)&Py^fsm@{0h|og$^+?|!t|k7YXHrc(6(U;059YoAU%mI ze?iU=u=)#opa5nB=%Umd;HaSkIPEe5I7;UTj^c~~m)BbX*lu+MIBMhqh?bEa;OKxQ ztOvq01;`9q1EEF7D=i8Tu^9kr$tyk@Gy_20<_U(3GzS*QT7w}+c!5)6i%U;M4^n>! z=#|kDm@g;~!+})o{t;8CFX#{~nITQdg5yKZw!pd+tN#%ThDf}D#HJkx|FiCcKru4_ z^n3pSa2*JP!K7rFfw^R}24?l(z%?PKK$rlu=?Q*TtpTgg1_QMfHefy`oWVqGMguDy zLcwhb5n%G1+B_aMoYiyv8mHOEZ6-%6^619f!_p05m4sgrnXio1i@4#;?TKH|&RPdl z2fQqXmzf-vW3bQ$Uj4VYM9svbZKa1LTt{VGj>*YR!t1}R--L^*xNPc69{z-9 zaa7DRTgAMC9>q||ncHzaqxZsx8&}HbW#s&*3;!;U-fO(~Owp!0$)4-2#eX^$E>`Fa zBX_js9+J|$WKuKwoe?H)!OVg8QS+Qu3Y#gK;1;&}EL*sPx2<-tQdt!&XRJ~8$xBv* zgK8Ap?HjggD!DciNd^t4CT*;NGYZTce**cj-irCMU=&r+>sKyNaLBL;tQ}!<(U`M& zj;Py<*c8YxQKcmL_xAJ@j$;!FE2k@WE9}r>dwKti+=quV*zaj&C++UUuv_Dk5$2QPY{3q3x=ia@y8N3Zg)rncFJ>ybAQ^6Z-2~bPR zk!iRA*36FT)6ap)>*1~j5=3mzjEwi~bUcZMr?=FSj@^749A@7MeDfpdqu5YXYB^>;Z=+~j(#tJN_lc=}R*YI5tv|JZ)!NVHELcmpIP}8( z8{_@>us=SoWUItWjt_jgp80T0sCG&x(7&n`9~ZeD9L z%A*JqCJaA&mOCf7z$&@nZ=_b7V8m2$>wyLd=Zl4vC#;_c7)?cKl9GH!q-7qE|5nio zuecJ3=-Ai8#mS%BVA?EXWlv9`k>Pux-PcK?>0T#2^)6DygP--@RcB4C>@ULSpRlTY zb)5h1nCNZtj3s4;xC;UPP{xxi1f?vZ12<|tmt5e*t&JC;uWNDXDUdea&a-@pysf%l zOLg@h%BXHmO|@%rv{;-6oPjk3npB$gZQZ-C%6p?8CMha2t%wNq&(M0&+>08OJeLev*w@j>o7INmK1r4MVO4RbuG%r+DAC?nfG6R4{_XPHl>oWfd7 z@uDj+>!GzMRrJxUk2B;yc;rP_Xxi)3=rx4a>+@)XlJm?66WTI?kwaVdC_fnj=`XfO z0Br!l1fgn&zsvxINBl#uKu2&51b^DlZX}3`6r2E8v_1snQ1=X=+6QNFicbsjit*l{ zE0t()8^~;vK=HC@xDcBUtO)=kNfGGcpAZ)$UjT^WQ4~;miEur>Ag-|Vggt;7Vy>W6 z5MuBG$V&G7Y7BzV4=zjul!ib3l190;O>_is`xa3+qxcicwY64-6 z(1OoZ1NW6a-MD}HOo9Q8toee7X(}FcQ0xa(-A?+a+1(%b_%q^Ynot4w2oeg!1tIYO zF#efPu>Vx}D%3p*0Q}Ozg@y^yh5-se0Xm4EzXrt&^$4hc7zFP5Cjw$9)LPFg zdw+xhdqaYO{>#|uMhM6ui(IbtyrhhjP%wbJ$CsJ%`Cz~@pF&{{Kme6Zhrs7J7@@+a ze@O&f9YVk_7nu^H0$*&XHv)tjXO94l0HF|6;{ER=dqe`GF~Tpys<0?PwV%TOhE>lV z12Pec0&^>JnXkS51lWd3r^1Cn1cr+9$Roh)qgD_@axwojUq)2?(5w@<+44EyuIQ)0 z&G;u2@;?z3J%kktbSFgu-ItqdOd%_b$|Kq>Ap$=v&$U|!$)nvp@d)U zzY#;sy3{?&a9@fF-gy%&e2^^{z2NWmoQ<*J~25SDnJQlG$`B1u zZE3;MByG9E@hq6_3;5aIvk=mis3kqY9P9}=zlQU%fihAVLHanIX{edJ1PNf?{$JBOuZp-|kG;hHD_$-9t zshqgvtv#kcbQTiR0&>l+t+zrx^Qp%8jRT*YL` z?^jOSxJHth-yG%E-t(1A4A_Uv@|rptTaTo(2#aq&tE;?rGs;ahUCA#uL;1jzguV^; zp!sHMlV#&;b>mGLevILQY1;zZfY0&oj1lK=8;b?wie-xt0%FAitda_%T`r~pb{R%E z&C9(a)V+g0e%cDWFUjPcn9UxQ9*cCH+{-jCLzbFT!e6zU?WRgIBCi$QF9{rSnR3wT z8gkVNNeZgw>Yg6VYIc#`&6LHlb8)Zf{cu|^pp&J?pnK@IRbkM?wE?cQJCX$+am)y5 z7HXYV&-gU!WNUG%&mX+-V?TIl(R*_gQ`LT~xXKt~bdWQL^Y#}rIm$8q#He176xxTI z3=swDe!6qZqQxD(ca(}PlMJD-vY5Lt#jj(eI z`HP{Eq_R3$uam}J^EH-(iZe83-t5dPQe2G%sEs1Uzs0MfH~@yIPzf$9eg%eJ@c;}j zbD_Up0>WeD24z601R#Y9nBc+^{|DqyMIykc&D4J$Kl|H%Fou;1qM3#y7y)$72g<@< zT5+Jj*MLVZiP5_7AC%Rl0o+uBK(w)60ss-`C5WHuOTp3Smp~t_5#YSgGQeO-ul|NN z%H`n9_%$#Agg4j_UKRjP(h87&oNED;k_D(?$P5(t#^G3~w!hF>Qwhw_%mJz<(*P$$ zRsjX6=|Gi6H8`@!0IE>T3lYBur>vQv^UGS>=zE}R4V+#MKO-LuCbtIg^%o_u?*N2r z*pSE@SR3>p`~M{V8mLwW6wVX?c6P}DoN&1r#1!Jq1)Ko3Y~%wiVBHxdgt!L7gl_G@ zG~mKuV+M+{YVxk^L|wSdI0xs0X8|hfB3B`mKr@(NkX>YeJ{JK7-g^Va3R)u|m!^MH z>QMshyeI&6?lyz*w-y5KZ)gEWkKY121pLBpDiZZ}> zAFF{X%}#JSSq6;o*aR+7Qx_QKr5~1C4u*bNq5fP8-V2mIFrI%oOnhjg22db%<^Ko; zL6o1scrG0(WF3qd#KfL3TqZQ|r`=aE<8B>DDjLnYPl^)*8uW~x#Oq{aZSq9G~+(N^2iUcwr$ zljSq}@R=DSI|csJ`;r_LCh061EuR=|3Gb~bPGhnfHVBW9&pX0+(yDhB{y0JJEv|)% z*(o+v`lp1YaphR1kFPXbZ;?HmS4KQrq6L4%N`h3e#!F1w<`q?rUhN`eCOh9<#JL-} ziDkpl;Do7A6a5M#R&>}EV8~5{J~}U+Xp1q$glat??t~F#yfKY z@B;mgOU(!;`h2C%BvZ#K1J444z$XGS-_@I21Sh?dBh^J$@Ujqf>XsFO`vPWw%QNd<>R;46oAXjFve4 zx$A6c{`P&@se)6;-uB)};7szIDuRLYdG!wy`=^eU1_I$JhHcDyv^ovOhAy7AGU-0% zO)kSpqbUq3-lRe$O%y?$0j+t|9iNjH{^Y$GHN4` z1(iB`+ca(%&z=>ZV_dvLzi0pYmB&WaeIC+31kn%fKWI;)!phYsi|-y;1B-h~G6Y_? zWOJJtp4|TCn_C=LDc!ruS!DSq*oa2;dpdTR zltSe8pT#S{Il=y^qEi&X$1 z%G&_i#&rYud{d1A8dPCVw+G;k%X@HI5C_+VuJwXbks7cs-s40MnnsLtU+)K9s`@K>D9Z2&CN)(}aB60IFj(0mhmi0KIfK0n95H1V_)C z0p^K!02*=s0*0d3@(=T7zy8BK>efr9z=J+_0{R63(E&^avit->i`b7~XkS_{TR0)c z?_gckjUkX3yaYS!ZUD2d+5n=XHuOWpgJ6)x?J&E4u?9^CNTT)ifG#fs4l`(>ul{vJ~ZXWk>dKo7V^H(n5U*+mjdlRTwL0aE{4+G*XZNzQxX#?V>%XDNygUksIIwozA7h#yQkt{1; zxO~O9Qi&o4E?wS5^UghHM;>@_YlSYk^Y}vJ((m7mOlQ7I)cab|_(7VZ^DCUTztyWE zNxI+t#}Xa+G_jlg5K~#R24_bkh8VwHDHDnFf$I86)zR)=DFVC*C21iRhLuiSJ zw1E=8z3o%FX*^`df zhUC}O#=5C1#qBezbz`2T;g7Envk6JLw#pcL{jSVpStd1N*BMy;eTR`!Y*a1L%&XgY zB`8^5^V$JtzR~MOdyKw>czyedm*EI<;uMNLTRGJ*pYSCvqq6%LT>jl6%n?@GMx;Ed ziJiF*ur%+82AI2YO4rEU3{u&9a?aReID|1$W^us}6>H$ym{YI?2L(M;bYEF<@Q$0E zFOFCUo#E(9U2@uY3>_hsseiRyY}w*lP~|qWR8dZ!%0C$=XdON0^?bFzE+rg+<4xm0 zpu0*kKt0RyJT)uR0d2t5;r0%}f>u0p&MxQ2Z*S@6(@a&Rq;rmgXMFnKDVL^NEf+0~ z6#vR2-aE3<*t6YvPu9CvG&^%PV&>`){32-Joow&4#%w*Wqxpx{L9_>g4%V1TBDjZa`ICiiPNa|r~#qP36l4jp+|!SU?q*c za7u{vip`?D5D_V(MS&6M5WB^^Yo({U6-I4c$}FhqoPS!!AXI|#qK*cvGnKQkh! zV18iCOv>7srxqFoE(*XGkt z0d4LD0`WQwW1?%U=9RUJX8FOPoR(~S1m1NMQ_4eCh= zOzzx0an=+rQv&JC+scd2yD1X~Nu8ML#c6dH`7(UJSCGB;m$hDhw$<(Duf<4}Ub46J zt9zr2<<7aZm%}3Buqr8N_KWN;dAW`IawS&s&BEUb7Z*2IEU#DVl!0v_p#DTS3=%_^ zEabHTVCu^-3J6gwB>D&V-6ut;fRFYkK+n7T06jtSi3qvTLI~CT z1PeYE=0Sc9H1b>_a_rteL^fRki2Qp2W(~ICm_qM&fn_y%mgF@tXY z0wpi7`^GF~6%cIkAJ7vhRDtZ?>R*Dr3a>zAZ4J!gWkeyr1;%mj9CQd)D9}OQw*by# ztb=Ftuk~v7z>TP7!YHi@5YYyxvR!VlH-!c^F3I(Bp-$o-pjCDcC<~)DFQUS)s%A|7W48^8t8bDce`A!B7(#od3!+k|SVR)(+q^Z5+_S{ap~7 zk>i3R);%!JZ^z(aPNGi1-%~q6ngrmsOQNgT2e(a}frkzhu|g6g@W1cJ)+z8(I1jH{ zgP`xE;GN4k2kR}wz=~ZRG_daC@5;`ZBvA7sxPZ|j8f2;jaF}3@bB|13cx096CSy{5 z4UY|fJAs&eMQ!9O*L_B4526{(~XypZlNeue0hq}PsV``l$<^gVy*;$u+E$e>$P;dt zCfRXE(^50K+Y;XL6_2)KF6U;K!n=1T>7iCc$BvcWXEt1`l9!s~ueLY(2M8C@4%_Yv z(yoy#+Gom&bmu%!9kL6v)}OJoY?u1IA)D~VUcCW9kbjU>zr6lm3t{{L;jDt})6;V4 z5+nHbnNz6VXX9Lr*@xXkR5rd_*1_mUSlz0f)hPkipSwLBT;8OihZp=*lFU?pViXvB zQF8v!R6g_u58_tn>y@U;;#D8aSnYTf0nzSqjHC|<0bHu~!V5;_=FuW`i3%J$PSX5J z#-YMgh~As_3@vBGdtN^NKW;!}6))if?EG#rg{4JDhrYsmb(>}`U$@TvLL^H$d=`$L z`U$^Xdtiaf!7HgV(49eLvO*s7Ak0Y!XOyod{B~EHL7tpeXg@#4UNQGxU(Ri60o8Pp zGGeGlW65bwxkB%yMBG?8H)Yt|Pxy+%uY#Y-v52qX*VV#fOqn-u2%(%t*`o>ODMdGt z6<)sf9dDKGZwr2Bk^*LidD04@)nBcvsBYT5jy0|ImLLx`WBXCm(^=f8H5yZvMK%(w zd;0qJ^P&0Xa;XYGF6(GHU$N~E{vD=qH`=p4y!zaGm&inLxqwrEYHa5O-mFvl2lqbF zpT4(<7k8|~Nsm64p65mHw!dC=GM~wK*P#~n>je~nh>E=(bKxj>%S*IW1xE#{rL`o* zPj9|(rRrE8-Fp9~#LTrZn9j0aJb2yzgxPYE{VhXaGliv$&J#u*^f6ai(-2IIfH%C8 zJU=+UmwD)hD?Wce_r0Rr{Xq!XTB^}($LniMeDfbTj5U_lcU+O4gAcuC203^v{!?i$F1(X6ne&-lm z0Mvk5u67C4!6)Ft|KD2y7rk7#W(wUp1>n~55L76@6_5xrgX+(KU@HdP@UjXci`;C% zg{&~)z=8dMMu}<=0ZaH%;+IvJOCZI zA_}VSs1^Kk=x}EcG+fqU3NYYI&>%ki65Uu)p#%ahi>i6yLECt6P@ceoGosr6mS8S5 zz9azmaAL#%u52@fRtztx{h)nOz+bvZux-pfD9V3ZJQY1`!p*vP;L>IvYekA6^~Nl9Go zg+zeQ2@0q`yIe_V^?=FRpRr3vX}9@eKQ-s8_1a=zT>EI*8IM!VajBa z##8r1#)cpJJjDK|OQujZ_;cZRs|(*{L^37=rtRGaR~j)1RvKZH{z~25xfs@DWQ2mM z>^CG+UttrcnUOKE4l0E^C?k@Xl$&oj2%6y8KJ&VvAfIEiEsw0N!otENqamb^QB1@T zgpKPzQ&R4_3nz>17Jiv#B#@-c+7h)8-y#0pU#X8gq=Pe%HcXQCrqS>XO?)fm@lI@U zry)(NDr;vUvSeccM-TSy-4~1;3ha4zZEF&F>v%KRv1ZT*FxWa+qAd{rxs%nD2E^YG zk=g*K?9qxI#*cNL+K$VAiQ415{ZV7ITX!?6#8&lJ3ayRKUGI28!Yry*h8J3S%-UI! z7wdk#6}_~%d)$f3BOqJU_=H2Jrh3}7noHuuk>OTQ|Bv~jp{n+8;N#l4LpH*}p8os6 z-p6?4cR00It6mRh`@-Aqmwz+orV8m;IXM8G$DHH%_P0v{H>(D!=!}t-T`|M8rEP{6DVVIxMQ^ ze;Z_Iy1QFJO1fK8Qb0jMU}@=wqqL+VARS7GsC0?6fYK=?Dd;o1==c43e*f&X zb7uCOnX}j2uf8XQaIkzS62>nsY@bPM5DQUvbU^h(OxDm zgGOI~jwZEhc{LI)LErj2HjE5=?w%>kU#9QapSh9eDvtr@*Du#Hjabqo)er(CkmbMp2-!J^4GMYCZ zXS(igx0%dMuyI_g#6rv9rbNc^3V$JM*#H+Y$Saq@E!$SM@>RY9Kl3nszNOi{{}ILZ z;F~t{GZ><|IPQx*SzeS|)*^jo9COIZKzGk%dPUb;=FaX-xhyQAxA^C#6Qa)>bY$<8 z`_fncP<&i!EM+V_lRU3pZpB1Ae@-3ehaGTqd*u3+9qQOfp33j(zIL)+E%vgHr1SJ_ zruV9_tLZ-YlWZ#7VSrKTrXW;EVqHhP7}B41C9Ga^dr)(oPUN8S-TWB&h z#(&@{1_J9yNGE`17+@_BHqB*kAi5X|&4+1#!$0^2KsFLufUV+}2?E2kuzRW1?SCCY zX>{Oma?CI-$W#cd&x9VV4;96r5e5rl0DsD5GVmQX82ja_%0z&EiB$WMMPdEWQ$}Ro zI5J-t4Dp8+g@KnJ^n3>3T}b#rEB0OF{S!iG3_$_6ud3bG^% zs*nK9Y8KdKJ=RxluuyGD7z-pV1?~#s7gvy`4I%W03#^u%?Z07xkeB4Y=N9w87=W0} zPl4UQ5D)~xDUdnLg7|;Y+YF#LY0%DV@x<-Et?cH+@T3P1&yrHQ6F40sl2jYMiIyi% zF`OJ<47!esvg&S0CcLn_`Bb9z-o3VmQxB=)`a*=MAf{#p+X7d+{tu$bd(>K~5N@iF z4r^p6MPV72Ufw&%yyLUpBseFZ-lpEb=Uemjj4YCf%>04x+DvaKl z*%HJ`eL~L|wZSkax9D69oRI9BHQCj%u zYexNK1!0MXSrRcNeKp~3=KY-SpBOG^*TV&$m(sA$)V?<>57@dHolUXWP;pP=*oiD7 zcIv0IeysM`$33*DO}+}8{r&Up`5Uh2yXf>WqZhpMz9T6^%Y!@xJSA_2mdEWZJD8mV z<=S$EcknVt9-EHXdYdD1&Br=NZy`(~IpoN$JDu+x=x|-kn#wJNFRnk?E8?Kj{)$Kb zGRtLnd#j_bZJ5g4FC^fVlPjlI+=}>id^0O{TJ==8Cexz(&5dot8s7Ie_|)4F*G$^u zr8yYS3N?*!WnGj zBmVM>8wKYM(YtF)Tdq>VBkdSIRzgTjVl4dO=SD-Bs z?59ywdhxVQ%|Va<$qZ~nH6raXJK|GSZ;%l8ub+)t2-F8lvz_Yg7SqQ&!WWpT_X6e6 zCGlt}ysk>}I5s;E`%SECF?BK|34-i3&T3_B#%E$C_BHdu=(%~siSq=J*k-pMGu!6r z5HUa7QQC%5b%=(zvD8Iyhp<5^jH)%HW85AQbgnDS4iC}O zo?g|BS*2lT`#3J^$1ym_c$J#tqYyVoweo!>otQqJ)lq0c#V96>iMWEn@(G$3Y5Y~? z0RLIvW#bmY-d!cJ<~m$!TmHm?%(zFYKk}r+KPlSpgi)B{d~#ROj^p2W$}$hpW|OzpG)jA8p2l_J)RZwSij8&A7Z5%PDST`UTgS$ zC5mW`5&R*QrqtmQ-g`ZxeGDzWhOq5ezV72>acPam*>56=KA|Bg?kwo{62ei|$E zU0Z)(@SnVpKoH?IXrCQmISA3KgZc~*Z3Sin2Y^T`U^VbV3UZ(w$O#nS6k(V)asZ&{ zgQ`q{gi_=J@QV~;FcB0}pBeO)8_0|tF@V0`6Q-5}ak%T!xgQ}q8sT2^8%{O5js8vDO8bD&aSAb1G#4?v1 zkD&}Ta1G_eN8AF^i%Ry=Ab>h=!NdXkABYeGj$%*xM!u^(i(J|mDjO0P+FlA@(Jf-F zJ!mTqGt?qpk~Q{H8uC)h;&nMUBQ zjV7h>f}?`B+Bh06U|X=M;w{_2v? zxL3PhbW`>a+S1%E7|rBnlbv$?(uqlENn*fwQ}cdRjfdG+>(p7otHDB5Bu@n-xWkjbl^tl7Q=eYUwT$^@C6Hu}xgj;e-Ml4Yk=!&;z0Z zw%1;{SGqU14C0m~R#{m0Ev+jN?7JgO`$ZftFszCwL#W!AGj!e)sM^R6+Ap!6C=BYU zgpqUHuKDpqIq^mAFxTgW_yYAZtMj9jy0Vn3evb^&LhHmPCVoogWN)c-xhH3E(y?AN zz5QWWdwih8B(m%D^zfkccfk12uYP>E`*gjG^(TFG@hz5La4RmX_3%1!G#l~qRVS= zoA{%JztUcO7aMQqG`y}Y$BJi0Y$|KYY`V`@#z~f!Vqp1{YErkCxcRo)@2^K?oQGuY z56SRTf6N9aGB!6!mrrj zqsn3p}udDVq+%+Ps zZt0S6COsr`37k}wN1uRIVw&SO5mgn3c!|=GnUBDy-H6!-23==RZ7d4_{whru3wLqAVy6XDKsq$@CON>(1|gCiyS!^B>+z?sMQ2O zr?ouj3{nL;YN#nd6?O%HnW#b#6*DmQ*-e0Wv3G#`Vb=<%tK{Y|UVvXD$Ral!=%qTW z1L?@I0or)X9pLzAwg4J5io!rw1E9=;GRzK|xeM-Er~*Jt!xmr=i3p4za!>_Gc2x_& zWvMmz1q!UW)d2An2u8z1fW3h9z3i)jnV^CIG`fGGE%nVnRd{Wsab5^;i=|1IgI}XAgKFDz&IZ3(V?L zTp-O1Qz%p$X!BK!V5Q|o;0>Te2Flhz)l6PP$_yN6z!263foW6y-^c(kiT@}K9vXu; zfuRSpLzyP1rGC@{(*Om4$W=bk2hR{P1y+$b(#>QJX&U^M9YBEPiTYFKO<~TLR!p%O_|q9&;2;AIh*K{hPEi&LGDZxyWe3sW z26Qq6!}rG|f+3`X+G~z64$uU1`E_?sH!IFm)lXA9_AB{5vA(%`42qTf;Aw%6KN?=PEZ0_3_{M*G|;a&TPLQApQ=sEX$Nj zd9`FV&_Bvqt-?$mZH+td{$Z1yp9{}i`W=@iGo)9%)G$3dvR`cPH{Rg&SVwnw|JV~k zH-wQvv=(6LVERbTT^;ZiL9FEO`*>yx{tGrs7$H=V0;52>9Fet`r?xPVCN--yBTs;s zxB3pUg&(x-q>^0KzDs;vzfR>B$<1OrGqH?27V=x|d4a0xI4Wu0`A&Gnl6ga`2Sbkn zG}GhJnc1&1QDXP1;_B>01xxZP)aE}MzME$MK3Gq6JoKPD9G)1x$SB^ah?e$r{6;>W zSNJVlN5WSHm_KC&m8My03=u_`&*~UCw5NrX@ZV%GZ8wa+$L}GsI|x`vR=I1SIU<~? zm|RAgQU&AjUT`XqcGttI6OHE_DB<{2bn8Lr{#`p2DcI9#;uxAD7TeLQafflYn4aeQ zVZUtrd_Yvu;oKut$H?h-%dF~yU2lkYeKz)WXC8Fd54$$D@EY_0=5{UwUe6V~ojC*p zUyKT`{&dVYl9;|&eDRQhfs8u8G%sTvfBX#@J}Y{6cXwJsO9jzT*LE6+8GY)Jgxt_- zkxt1FuAP+dm4?&OQ324mXvFrm{@- z2x~kG8eo% zt~uLUd89m6q$X{3aMW9%ma%iiSxqF2kbXU+;H6thEMGBoi9bm# z>s`gn`yBpIoUgPnTfx4wgU%$|%7|cT_WP6(Ru;jDCWq_N&Ay6qM?h3xp8DP;#BMN< zqpo0A@NVbGkG*fZUcTa%e3p(a9%-_cc=XNY;*9Gi#4(>IHD>ao6hFdGdCX zYMF^$g)7k2p_UC!Kk@vm*i06m7@cv+<>(MYi)Vf1Q7GXB{Fmdl^9-dgMSfu=5 z4efdx%bHmz>f@~D@Z9qIo5uI44H&%MXtA#n+*D|T-34^9NlfFuG<`@&4`kWoGO_A8 zQ!|{1a%@UzUM;s{PsWE_THh%0nrk*vnm1)T3Fx-gU-S(ew0^A%N(*X=wNy9}E26p; z2q`#$Exv9E0FUG$P=y)107SmB0+^{C1?0(+7eF`9yP)aj1e{l8-av+lTLS$HE;r``fU}432i<_SA~WU09sLif8F`7Y!m$(&iL+pDckTN zk_Q0OlLBBYK;nS#Y{aD}hyddCguR1ITrXuCYM4L3D^QdVg2E{fOb1KAltw# zk-S9A_W`)y4h73!y$`05;RW6XZWw4*xc?O>&|nytvzG^Gg1E0Cg!=@Ei^xTz2#MMs z0YSFydD$xneM^SvLK)%zpwr$Lto-BwcrV;qaB|pRPDSXWFH8`DgY7sLhRa(-D2hi^ z@TW~^ancj68_KT3at9{$%g@2bK{V5SlD(7(ShP6&3Ab@|MqbEo$cJJvN#kN=-!s71 zsj7r?5V|~0yYULU?qOsR&gYt3G6tE~)+}ln+`EZClLZLX#K&(5RoqY|PxH=T4j>6< z#!U~ik3}3c}PQP_Ig18 zKa&Th7E+DF${vGL*myG~0%A{g8RV);xj3LMU%~K$k2_5dm{oO*+@A|c4Lv`gW9cGC z&vy6|fYHyoj)`8W`7r6JyVLykmb^dOy!^ryT=9^fTjyLVh-Af(vuRfJ3C@*Kj({f} z`Gpm^#oMA^WOLIObu6E2_y_PSO4C~0gHjjp*4EcDpIkgJ9lYH*CEm4s@T*5$PU0(5 zQ?|w2^Ovd^zb7A&M*D_~F#Yh*p0i7ZZSOu*JV+!quryz2$sBlilB}`wAoR(Bjk!i| z!6SvFAe$L0{YeDWg4LR9TrVJZ5ttPg`V;4SM}B;wwFXZ69}7VkHuX$$N_C9LqIwGB z>EV1y$a_ny-$gENFTB%cq77PamvfD@v5$*NCe+8D8`#MFdax%%Z`5+Sds{6c)`dGj zUn=8K&ThSTbtO0D@b?$JoSy>XY3~`N58>T>4>NgN?4`($h*hH6T?$)6Q&cd14#_ji zSNJyLdmlbVq|Ito3iigI2cHK2tdi!D5PR%vdAjwQW)UM+_2Sbho0^^fO(I>B(QfBx z1=EMo8Pqm5RaKww*#+t7gpLlSE>IL@Z+SJc_iju{T+jG;gG!fS^@{aG6KQ72BLNX% zy~<})+3UB-))CZs5v+`xLyR&5^krS8A^lAZ#rCH3ItJxaA2t;Wq_jMTB70>He|{O& z)6$ah*6Ff|RFb)$>Q5@9p?4SeZiy#t@Uu^R=mQv3hAmr{z%*`D^X9g3n{)L{xm|$z zHAx;pi}AJm47Ay)wR|bGv6;JPtp1NRyjHR91zu~_c)p({Q#B!R;~<-9TDy6N=SM)X>8`4ko@=$#?pFe@-?6w~3Brlq4afujdu`%tMlMTPELm<|*g5X5<9b6_y$H16 z`z*DWDtq%ounz&i-MLJ0M4?E47r2H*IS}AOsfr4Ks}Lb_q~>Oc4y=<%uuY&Ivtme8|HUaM7Iw!;rKXs60TV(nwY5zUg;0XY?#Sj3q)-)j0TM!By`^X$dyD*@$lSKn% z8AYgJ4snNrCm$>}D*0IM>L_ULhzr3#Nyp zwFAs9NNssN4lLK_2?!|swLrw8K!8~6@?HOm0!x0GfQnwA-u1g^RP+L6S471CX(FA3 z>O>u7k;r?QtOV-HkHNQkz#!mz0?-QX``>zlQowo%;=#!mAV>?%+JaSr z1Qq154FBVpNtA9wS3;YpZbf&xI{7=Pk`gwdW7hamze#Q6_pe!q`3c** zCu=IQ$2azww?nZor!nD6MJ!RKrudGbI7BLbSER-B^x=x>UQ7%rj>;c(Ne`o>2a{E( zhf9)2&?K{d;tY3rrLQKQC$i)s)ROPen3zO_@9CSCR$mcz`r-ePb17a0XWHhyo$fuQ z1^kgD6$~tU&ezMtr^agu{mufOs{S_OK>^UrRLEmQVrePAvb!p&(l3N_4W(Ft4(K_Uv0%tpjVYZl< zBX}|B=F|H84bllQSKVgqPl}m_!0eFqgLdz*r-3dfVP8!3u5%&cD*Wji=BgW@iVE+Z@$voENq^6yvp|py zw6K`?;+a(D^oii=qD$u zY5!$kL6~ZKH!xh2!phJcL6IUgnRwMca_BHloRnAS4wu7+h+Ax;IS-x9)3fXpWDlFO z-w`Izko>rREuyHj(d0c_rKiIyHOtC+rwiZQm4gMBKsmE!Q3h|e?H{zu)e>$p%2Dgm z9-=-5vKX!i^qGnhIznTkWzo9_wW)pUYjz$ZeCCwPyvjHaHXnwlnj_x%@iu9c_$B@z zt-s~x!@fhbJo~)G1&=LA^0w|zraq~lZ%Zs=ZhI?rXiacR^q)lXu%`&F9lM7)gk3VP zIAs4U6)Q6E=AYnB-3wXb312*Vc}SYtOp}vPk_tg#->X(L5+#|e>li;hZjF}ljUOuM z)Ipe1pW+mZTS-p#FCO#lpEdVA3!u4iyyej2nKq%*(8_kKy|LAT=il;W{Y3!I3LX5m z7OpY&ayxn!hZ_&1kO*|sf%r?^^bRT`Fg^j`21+$Wr3LCIB6ZQf)S-8P&5!atTu=Io z+vwsb$3to|K%%*408da6Mv&fZ2&aX7GeK}LF9k-F8n|)|+5HzuP%PbQ5N$S4WGgdZ zHV|hi(DUv?KsVh(eiL{K?mm|T^g-(~psH&30T0aaQ{X&qeF4yMxEOr2Jp%x?kq?qa zzP&;E#V-%!0l+y8iDX@Nf!Hh3wf@(Vu6qtAWRqvU{?{; z3M4^0RstXhIXC#bMS~#v#xQmvmhW)pr)*yX(-t9L%3t$74nWU}X8(M~;8RsQKQI_1 z^j1oYJrNkwubC;kcy4Nc<&@8<$?s4Z3PoQnEQ??$tb{9GtCvw_EGrcrq{@KhD`nJS zcxAXbV%)L68@+`c%k8A?I2FTcPk_)F3e_E{DT($P<{p8&6v$+D7mwgw6lGRW;+i_s zStl_M8FmNXCKDhuRWh`bzkbi8CZDHQOG+wftCK3(n>3o2nXPmltr(|Y&n#Io+(wYP z!^csWylxb7lxi+H+H0cuxgYb1x$BqP`_wt_M-tqX!FflOwxit2%S}F6gbxscdGo~B zevP$V9ujRWh0kxRoK3z-zgc z%-NV+4=?2~qN2TM_=98EYqs*iC&!5Sm3#&X=BAMs7qL|i%yaG(al(?+8yR8MaRW0N zp&@(zjn;P?>1h!urrR4|`VfnVSJRQN)#vUnxolhftUn6iYRjduIPb?c$ZiP?<18j{ zA+i18OVjwRt%3KB5Wd8hbpsPJ0lAL}wPn3sm`t^<^`Fwxo=SXIKE!dv`i%LGpM)H( zk9+xQpT$#$_MujXUoC-O+!_XbvIh7_uc%1cx5tf46_WLJA(Wm;rfHUl9U|Hvu&46s zNyAseOD0lI74jz`w?f)V}_G8N$m$vtM*EEV86> zy~xt{m6h_7urHFX-cqGm%BrfQxi|wLAc?1if5K_`Wa?sh%5auN>d} zNCpA}8kcI5$DNIRHVvsdx(bMI1cM%FnQtGBFZ;ja5Zlqw`1aF$%r_`w(C6Ub3H$mg z@z{nA-rfHFXT~pu-q(@tnlg;|mGv9z`Egx$I&JcM{&M&6;qRbAW_g2R9DTyU#>V}d zIyt9*YJvqnggf`1wU~6+A9ndYW?SV6?C~?xJGJd-XuKPX$jG&*@=p7M1|Q~q0WoC3 z$RSt`fCE(Q3P}8JkR#BU10VpI4Gjak27M8jZZWw)BSF=d&X)jGvgTz;q3HOhBjOZ26G-kEHhDH3{ut5ms$PdKw*Xl8RhehKRS~z*;sHEdBcBE?G zc`E5Wk6Q2COU}8N?f=ogwbaG^*$JPfXp~6%{m88(VJwo~!n@**KU7HW(!Qj|4N0xk zVF+h+E7ZZ$na$4`V>Tf%7fq23#`fI8o5x=KmG*7?mMHgaKT+?HR9T^A3bG@Fl6lx1U%8~%&Yw5x3O66b zcogb)zV+c4k%fi#_{vFaW%_f?!hk&EWlyRy!dvW zboH56k3xZnYcb|%M~J-|JI)>3S}l=%4-@Us)J2`6Ybl7QTXtf7`!?Iz_4}?F1RXDD z#t*tNjf8Xb-jqDcK4=~n*L!Ht68^1rAA9Zap~~61-rl(|%y9tvd{(|rG}<=F!8)7+ zy;&nm?}JN8NJ>e%S<%oPp5?t=&B}T9E!49m&Lnm0Wkcl`%Fsqi(65w+&9t8}z20V)jmxNy>hEKbyvNSZ0vo0>T&}&{{Wy<3{ekzZ zLGWb6FFX=H;^)7^o;%dE7kw8Ca(5=fv%hcm(CY!z^b$stQSu*Bps1!hO8yTi{t`|< zDFs(_s(>pCNjMELynv}d@-4togNh}5cnR!1t6HR9@CF2HZoUDw8Oo!C$`nP^0F!UH z448bhuYhL@jQh(vtp>5x0WfK(1ojrjTYx=}UIRm~7x_)13PdN?>w)T!+ya_^ssJdV z;@YtGf11RnYH$rzM-b2m#*HC6Q0fX<6Nt{p)&5WKB_=@@t^b@#Z<~P@p;iYB%*-Be zd;EIvT#H`tZLl6ZH{dO}A5$M_rZxNpLudopG;0J+R2d>sE3iQu`e6!4MlD>Zv=uCI zvEmdw6R4MK5 zJlkVk=fu4Fh4l?&FuHZJ7bipaIFG6;TqVCFd@Z;|T85cv2+gq&=X~r2ZuS*sC!AbG z`Ka4*&2mcBn&c#AEH;l*6(4X%fZ`5Zp-+Wx?<&OvcND06eU1)J%pu~Jh?cn8e`mqjzM0c~1WZ}RyNZK)pK#1S zn+%0?G5n??{>p){e1IPB6cimt`^{HO8)Wqi(t5eurVO`H_cb%Ti4`Qi(a z5Bi835lbMjzSWnYnYXzNcUCcpTr#J)U$~p+%x&;)!2VOHA39-OkP$n z7#rxVJy4R#N)t5pl$Gug-6=6T*l;`Y-RG4{*x2+JIOWf&KCC(y&P!h$xfU`to48PM z)xB^5-ow}(M7()C>X&X5`dRk(*R(OR#y{DX2ySRTF7K;;t%Ie}wzO$M<{!KDNx}~+ z!Caj!tV}u`2%7iBzto>5pZmS5zh8c2>C!suuvHnr=h7N*w8AGL`uXubU38*k3gIcn z{Iqw5dydxj=?Z2%>p)$Pv5QW&R#u6*ekk{R)wZ7hb79uB^4t)H;B7P=v<);>wD#}I zXMvJgL7DA2YOcGvuTyN=wXZy^Fv^JL;;@OCU#Fdxa6qtm*Arj~uA2@KOfGc4<`SE& zQT;3!GD9g*gtp@= zDl6;%NHic&l5%!PEN+Xmlt;F$*Ym1yavCYo+DWh{mJE%IUI}Mo5MGFz&8yYKwQ`fM z=T8UH%>KwBa1b*xyT>t&6H{vIQj@%2+juC6pME;J5-Dr{=a+87Xo_499lyO)n<{@u zvG>hKrj%~aBuwQ`d~$j)JYY{{?diGgecXA>^o}ZfFCw=+JNt)RClh+-E2@83^%++L zu;$t4C{+g1ofS+O2?nx^8VUXhQTx>WG4C@Y*RudJGv(2Cv}TVzS_TT<=kO(euA5dp zG~5D@f^=qcDSh;R=xOEopM5#_qayQIgOOS8_S->&i5~a0K`%7YcaPAT<)k(|W{oPe z*l8igED#s}(E`vEz$fyQBvi(|eH*}|JKe}wFH*hY9r}l5_q$-N;9S(dsH5Hupc7@8 zp*%+n5LpiZUcq+&mHsMv$P-GDhL!+y^bVlWrMCCCnCeXjIOcQ!7i4>W=|#fLCI9i( zM=%!@w7&ZSY__^j;ASYVoO3@+9a0?!Mj8mhUWLGc=Gf3hKgb^9>i(Z0?8sOr6gCDX zjPhl@7z8U3?LlE3D!74~%t;T-4p{;vFb5FtO)oGDiBX7md3-1sqJqj+1#^0?0{m{b z`~N1Q{u)6|G#LZ^@9_c2pTPv)4Ztq*q(Jv&tQBBs2Us|222x)D+V%|sbJTSfEGTve zn4^4i;G5c~#h-XW|xYupsc!FRf4j0@#h@guP;cuScq>bko-M@RB;-(mdT z`iXiZt5)qgZK_F28Z#gCR+b;gKH1@?J{c$eZg{;wi+oI&%Xykf^V7AO*aJRD zF4l?gd~=DsVtM1L!I2oX_phVp(TBgq5l<~vLH*Mn91%tELC4!rK$}KC_LYr7u6;o2 z<}KZ;GeIhUFcv63a45e;OWkc^W*w$srWOhRpuK~W!Na#H=YttFRJ%_RRm;8u*&Fyw z(HI^$C(kaA!s@)AfB(Jb6PPyUN9*Qfo275xM^KEh?U+q1r8ZFJX3&}WAm=uZ&zrE% zluo4qMkEN&lnL)@b_una5e1!(CVOu!`FJi|;%L&m-QsSJzSU<_S(g@3x*qC7IAha! zu1?*+=sQuhEmDqnDmzo9(XpxQ^eEM8pm+1B#v^!`WQ^w?e-?SEGPY}p;anG;s{hm& z=e1^sO~V-e%KHZr(=W}R>_6RdCwO^{p%U-od#}U zo59C-1e9Rff5w>IIN_JA0hD2E@reUXmfx-PfpyP=?nq{v?P=O_70H{h;~5 z>*IdBc5QvOKM(QK6=zPye_HSlW=TKfc!@l8WB;&1{F0I2+ZfmdNSJ`cx4<4L9S8lz zb6``PZ-Gs5f8yUBdA|*stCPSbBl!*NptD`DKZYAXWfchr@alj02K?LTqVP+;A20&7 zEup9%|6sv?0qhpsS)g$3=>rJpnf>cnkDUWq??|fJX|nv+8g|4{S&xvns4C=-y|6ojj53u8vM}@+&7D#G_QXnk#bX@ za;80bYD#=la*L8E27d#G|FbR|);$()<_-T1c9O3y8%`v9clv_0ErFwESa3~Zt2y}l zzUJr+@(O$fLkw_jbR}MOyWZFB7N(~&Rk-y$4Q(X z9yCQnb=hc6WPTeqNrTCynm0P{5?bip?DfIMCK35YW1&x(O{aJ-ubtu6N;4Y;)yErI z30=En&h?mXwdoBr+Ha+Lo?O(ulhA1#xhcJ2#Re5_;UOIB5VV;|{VxKH_5n335Sm4?Y=Hl_}xJpR-cgizkLLG@oi0O|kTTw99;dY!?7s{hH~} zX_IzOh(de>kDf;Is)Q_*Klz=WXVcQAgMI>MI9c4jQ)+ zP56S7*(MP`K6nrEdgKVr<4@F%#?r4>;e0X^d+%s&PDNkYH`;=ErVAA+zL@1pxpDVV zq<3n83L6#Ua{A-BqJk~^-Whr{^)K2@qL$1^e*GJEr` z&v@)d3ZhtI^q{?6)TlkZyfNkQbq2TcVdusKx5)`HPiA=vA9_l#FS<5HH>Uix{NMUD znh8S*QrqscmIrHfqmvcR66MC81eQXaneRW`QH#6cV?1!~@NrX)ulQ$D@+bY7S|$5K zeZGrK(>Hk=&AYvRZT|OPv_L`>_+8vNo&lB;(L*wdK!MM-d@*^yX^1O#?D1jhO8(T$ zfLMt2Fm;@D!eZwaM~A(a&a{Qf+cVyi=jS`Cac|uQPq2F1(Y6Q-FRN{I!ReltKApu? zQ0|C|SD8Un-+=5x2|HA@3gwDT{*H98ZUCzdCGtSXN(Q>y1q2$w1`v5U3zyamKD507 z!gHek6R)b>1QOPA@vqScwYp&ArsCx5L3B%CGtZi%8zb4}QF_hCRS;3~+6Lwnin}a! z4a@?S=q4_9$z6tW0_!0U212E~1?>VA2ss;MlnR`r15*BIp!^+R&-HHn&lqH)+kfG+ z+k3DZ-~x(*N=#Vv(ji>B2Xd?2w5|&ffc)a`i8GLScB49Txc*vS((RYiL3guABzp

$p>;##Mp9Wj!~8fV05WsvZ_y7kkGqshm1hV2Ue8NPuZs>PUe6&;B4Aig>rBaJ zlwdD~PSZmBPO=pqsKitu4*1sT8P{)q9#SULVE4Kqj^BZ|s5`8NS12u};7B$Z$p7|5 z(A-K=05ydi1J&(j9a8&40&}sq^j7v`P29WQF9_U-*a_NTnGi|g;(R8u1ino6yf;yMkW>6$|G&Y@e zSwe1N4ac#>q2kJO)mPUCS=Q|h(zWohgsq0NG71$2PuW@>vQql!IR{UFE-gq+u-LTX z-iWfdF zE|VMW=#rd~^>^#}O%VrftfaFZgLqtxn8)sPF&bJO_n%faSf51>{<+@J8TrhOy5ac& zH7oBXaHR8A-pK3_DIXJXS~*_SncJbMdS>cJ@tAqt7Ahp&f959enP_02^*Ti|dbgxE zGas+&>ylcUHv81K*#p}q0yeNQ66Rm{Z_fqXJ<^pnbtw9n_()y!fV5vZRjRFYIWPIR zD=<<;(@eS9@bM(m=5E06X+e+a#OQV$w`a~d%XvKp+czfaU9HkL7we;5J=102 zUuwj7J$^qg{`JVbr5~T$%TsT=J@-VyNJ8t6cd63M1;j7NVMCfb9*k~PIvyk!$2nB1*5=Hi zj@rb7w@|q}ZO=yR#3ajb@Vpc;#}A@NL=vfoF~|wl7^ulz<;iKpdEU^Ov#MZq#Au=^ z+8f8%x!(Z1@o)O8!-MClLQ2MJpH?gO_8vG-hl-kVt4#S-@3u4>Cp|!T*j#zXE*e|p zs{Jz#W@|@gI%jN$U#R*Zl!~8Mkjl2hF8P?B=uTAziV9xJPoflKSUFkjb!dtC+JM;O7?=#VL=N$#x zgWv4!dFIQ9ML=yC2aE5}&g7b#P`h~QD4w$`3qO4a2=^V6i_ z=vB|0sP#ja+h4cn*!4hICNu|AQ;=@5-9KD@)A5MR+sGnQ-NKQVBdvw|1lKi_^3Uj9 z3`S}rChWpko~{WD`0~YkWQf!2Xu0+280XG?x26p@kL{{JvI%dq526PZ9)Vx|_#J+Z zs9;7^9OlVJgnR;%+}XAkMBkN zE+5V#JFA8H&{ZrADMYyY7!Ko|YF;z)p@yAkUb}_=?UivH4?_*KO?QgTc-LVS3R%G- zgMttL?a~fBuuBz={_WBze9*)?22DUni3w@^0T%cf;lG_bi0nXaP)MKP-=z#H061g66G2lysuG2mJd>>B7e`~xO%mmaPQb%SPl3;Zur^9DAY z3-X|ZGedvKffWvTz33o(YcxS%%DGTIG{vG zw+0XWfB}94SU@#l5|;!8PcY%ss04k9zx)JRSYQNL5H5rugmWUF437FkvJ;>ZZU8qm z0hCVwZ-;uZ0U^V`asS6o0GtGL&}||x+i@H?U~;2?Tfq2*QyFa-U}9p>w-i8S=12^u zL8xn8S0HFRHaeNKeAIP7hpV(OGJH$v%6GI1f8+P$pCc_uMWcTIny#H15M@Y?!ZNVw zv6Z&ks+N=57w^tz!AVl!8qP2xRM>Y$OTX6Q8$uAdjf7{9NtNxsb{HF}qqP`OxRrP(*NCVG9}3s6j_!mu`j$T@+RGnVwqH$2KcS!c$$QUNobS_E z5%&fO#wJ@yVDfv}PeLbqA6~|vuJ6pyAef7kF^I8v+HtsUFC5IXbSf7-w~(NEWnA0F zOhrlm$Bp{wQOZf`^Ll-kjMtq8_ro^vW+*(}rj#mq01Es~CmaFkgn0JNQoklaHX-d< z@1(X5`3*1evKmgC%1_9c^F2(apb+UDK}(!6!^B{lcV1`~R#fWm_`ew<3cg0X`PC}d z`-9DhY86XPTb4nFTdNO*n97V~e{pryJ$KNRbNUl~?OCoz@YiwiCdJVRyK516Hw)Gm z7I(VO3l=a+^VmM}so2(x&K9u0ihn4|9jhd$JuG7@!s}5~G~A#XzLMiwBTrFNQ>Ig_ z{#4eb?o^Izj z)PVyhgG}+jenP1esg!WQx`Yp>gnX{Sbs$qJuy0q8O%ysXQiG-?A!vf|3_e6m2EPMs zQv=9CQE7pkUwo*T48VgE(ffo#bCrx&HQKq?#nLs0NALjz{uMgg~jNI8+$u7RiWQ3AL^(F>SCyOi+jP&OT0 zD^+*F463IB87Qcg(~e-{K#qdw`cNP>z^HsiIG_vW0PytxBhiC{(m);2}3&>tjzgo zjEs>gY;L!%ak7NnPs+bqvOT{usG(*gAHG-Mr0=$Pu)K9JyO^D)uS72&3Qh#|{DOt6 z;~5()S(T4gXsr-7-t!@NEEf}Bl-U+rlO-M-v2z0-y+GsB6>T+U4z-k&#O{ZM_R*}3 zxwDFdlt~v=LQZ}f$#=9%u6XI>S|~lR)u&ePEVq4~EbUJruddn&bI$0tuTm{75nH<{ zrp?xqw8W$CrNg;SqdHiCo)!%2SLz z!HB((oYd&(-m0Z{1sb)!DK@@`M?7{ilcn-hPh`4fgU;^wT}`IpbW`%cSzcb}2nb0} z=W;3jVZSYDx}#a9WBEmxb!PieH7_s#aZ*7!_RihCf?Ii57#`0}CT`Mwa$gX9Yln{gSsWfS=v-l3@6&m1EbdP7SnS{3qt#RDh za73cs53exRp6^%v_O_I7kl}5=C91OTY+~sBHuG?!E^}$MQwM$e^P@Y}?&sxV2mZ!v zIe8mr22+ZWEehEkw-Z|ova2;9Pan6dzao>o-iV0g?nH<(PW`B=j8*Niq*kOz$s~+H ziDwx$oC7XQ`n4jJ7x%?0Smi<@ z`t4g6x_tGw+$yUx-@R3Np}k&6J<*`s?eeC9g}8OYRh;+QN_XJ*)3>VEuy#+UTJ2IDSuIfbVPg?>q)=^1b~8KiT-C-x+DBvQ;RK(4-eAPR zV2V$wdLOU1o}$TjW9t>tT(U=+SB$^kx5YM-dP|Rm-5Q^Bp5I>Ix>p6quD{ZckyD7c z_2iWC%JrRh*w!+Sq~o*b1+qR8{!NUg7njtGp8ELtuJV3=px{O0r-8@t zNcof!cr~zj?spe)NKT7I8sPnR( zN%W+un{!y|Fm;)$_DNtqES~b~$19QbHJ!bkOIKRw&&52ZfA3`p*6><*F;mZD>u4Ts zRXv~2X@_Bjxdv{De>jDOe&z;i4_rk19QVw2oQO@Fd95J9lN4&F1$cvmGN_mjKw%Os zfRr%0zkmuQ z2Smel*&zs#NCNadmb%pQ=%5S%I1@}rUpUbf zJh>DKRuf>$Q#TnM`I-wmUO2kEYl<@V5WGPYD)x1cAwA&$uCgtHIMfdIim_mn@JV0; znN7lcQ8;Riyt7)oO6% zmOKU1xEG`NQ30VN;}l2p#CuRJYY*wfT8Vp)t!YDF}g=NX#M!{eGMn$kET3Mt?> z_lJdVWek3nb-7&>^>I9HslcTkr~g3wRat=UE@!-8SLy@t?q~Y`UpMtWoZkAVIGDg2 z#6Ly(j*z2VX|tH?rqMTTmv8*Zq=P~+JTB7LwtlXCo4Nb?k7PAzimBHqRjTppcN-r@ z1~_@#$nIr~x-zOFq*o>1(vTSm40nid<76G}10T2C)V%%E_pPy6w}+PQ^rk>Mw z{hpnC?~P-B8>N0{8sT@5po%q~X=9}lZ2LVW%)c$Mckfn~4x+-OjnJr`s1o1R>Z5ni zW*_fCy+@!qUi!k0<3SM(uf>E_dB+g9YALo;RmC2Ghr+E1bQnB{X!luY`wqQw^Gmxd zwFczJ_!k^ruIV;=mcl1grn=r6X%1*o!PfFVXnnyZQ4b!Lx!=ysy(o7Q+K_pyvnjRb zL;u-QdXLYAujR@^!18E-VfOh%jwBB8>uLJ4N>;9yyX=1c>39CT^gJ+o@-sKZUUIx0 z-R*H%(X{UIJ`)5-B*6O71_i>0BJ%2fYyhss{)W<3n>2@Ngts-CxC| zLJ}w@@*;3s@EcUh&mR%^J!t1APoVfx@GSfCJrli4+3Lj1^+fB;a5!I2DhfY;Lu z(i8{gp1&Nh68}CHr4Auv;WN-D2{^<5$JblNMH#K#!@$s~gn)E+halaZ(%s$CHIyKs z(nEKHNOy`zNlObNAuR}sB7*N8(DR)C`S5=6$K10AW?$a-+E=axe=FoR68sBQ(vkqG zrXE6W$>Saf|J9-^mIQH`DX0+1U^4pKf8%`doTS|ZgiwnZv3WgEvZCNC&_JLZt9SCbp>Kx>wUu+ z2mNhNkv%Gy>yVI~aPJ@$5-Lj4(3T+ZceFg3o@%#gE8jhK}8?+0b$$z3}`-EyY~ zJkRZG&bR?yn4GZ88c{tTlajF4+OzDGNjS?V!V3#I9&i6mjEwE zIdPZ$%x`e(ndPKIhWSt(QOY040KG^F%)cQW>+zLRjn*C-lZFV@uf#j8y^E)XSIvzd z_r)jhi{!+i1}bF++!-eWBNtIr{%lLU*0U=s?i3P;G)yT4-s9**jJ#1XTEF~`kE&hy z$A`|Y9s~|Fs_>57vfi=B)R}k`7@{Blz~beb^PwN8*{u$q3xNS$#L2G+ z<;}}}(bg~ugw9y~WafV-&-s>C@5KvvO}Cl@GS)-Tle(#zIydKfdK;+|hD*)mTdqu}*{{l2Np@&ByJy zNg>YD9-A~~v^7+3V7091rxFR4+r7t3NvV8tSk<=XhN&$L>jjD~9nnpxV-W z=V827aL!%My-W8t`YPi;x^GZ8yAZM{gLq+uk3d)*rU<;i|Js!w97DO&!2igVI~cLl{i^x^r}1U0iO?RLOwT~%Z^z{MWpwKdx{1=jT=I!fMDI#v505xN47!iXKi7S zIUp$Nx3=k*^uVYOW5!W=PM^XVm~8dh!E2LWU!4de6b8;gkL_e z@SYrs{O#+Jz7PqmdZUr(L$gvDNMtD0Vu%BLf^pW_OOgf-?I;SU;>Rb42n_>8=Cdet zO-O{%4ck#=8M2m7MKgWe)%PXzQEY-DPaoKH)4QkI>S`>y=n~J>1*QGKn#w8O8aOxY zo_%@t&@wctxw=99-Aaz%5%zOWb^c1!QBt`1;&f zA~63)YiIY-gcru6HFVZT_D?p4q|s&we^UQk%3*VL?|w???Af0@y4-{^6XH}O*JHPh zIX2Fr?e_ToB-CRAIcKLl@|3-PFKQ>CvX)#Qx| zbxl7<^3Ex!on%8 z8bEppvk;5>8jngxudwO8W%14`#WT~wBJdA<+~b%63Qb*pKbHi1wOMWSH&TuEN*1k@M}DtM*@TevEJ&Cowc{GB9N`L-G(;5s)Bdh_a}M*kdpWp=pv& zkw`nT>*|kCwQ+tbqE(umY|(3@ae1V&F^NXA&@InEzSmD$eUqO&wa;Cv7Jfx0_G@t$)PO>D78`Z7w1bh-Vr zI5vkm`3jO9x^HXKU4Hz>6yre(eEUSAt;C@nW4-bUGS#2niy~%)FCt*4B;)k)hT)_` z5y!?>kZvDPRb}vi-a22v5rO+!xGDge;LaE9wG{x(_wbhhNHt+ktij7{RRB|Uec+{% z4Zu(Wb>QM;=>z;+4+r=eZV!M^a|k4%yY)a4j7kFn8lxHiN^@oFLjqxUZ2#qY?{n*tB)<~vlm-C{T?OvME98WyAvp@P2~4EyZ*?@xa-1)hu32HJ7%;u8eW7CnO9&$MGBzmBEM7#?X{P1%qjXBW)& zJ_^E>LWH-qE~l2L)J9L4!x_j$Nscd*MDjGOL^QDt)39O3%3>l=05P3fG|^dypN(CT za_~9(9mkMiM278tol5%Hew|{R4Jq_#XFb_Fk*5XdcN>=(p4Ka3kD6>tN{9s_&tb2H zLGAlqlj^*JUQ*-;4Bk5lSAC9~RXwKSkENhseBkgWt@-2ZFYi^(9iJibxxK@TuTIyN zp7l;^ktVs&sZWkUOSL=s_r|i^&7p=I2aPFANUaC)lZSC{PvfJf?*~Cv638v*LrrS# zpKmhB%}@6D`aJGGa0}5L$d4bJZ0;M>4G5CzE$P?3rH1mXpJ^jdg!c_ESS zbfVd9^K;i>z1-uDti&Hvo(6o50p`KQLBY+CxKH1%dO0Ge*6@1;n!}wYfvm-qjK`{F z5LYckWcwjE^iJ(7^X|)PGvE8af71EUPv(jd9Z?wf-o28n?`4fr|GZlCi2eKGUeN(` z--mA4$Gua;W)wd;@G(jpf+v;@o8)~&^{}p#ZR_36kCR+>&@O-9>)&&S#I>k8Oh*CL zX#uZ0bzk*Xb91$&eWNmyfbr_tCsXRL1r6Yc+oc#jFr~E?w(~_5CJs=qUGvf2+F#H; zd!S=!99L~$n|lz*hGVe zT>2uVU(vg}4}uutNUrRPW%;ZZGvYAiC0wRgHROHFphs@vR48|jCgeZfnVdN=#+1ip zX|4Fw^EQP<-AX9-6MZx*UvQUw=7_f<4|`Eaz^p6-+H}vMLYRX&E}bNO_MiF-ap+iO zidwGAzRe@1gP^G3T$w?Nx)ixr&zyrCUYL>TQz9<6jiM)p8vAMl;d$1yzPtBQYVQO? zjrHzu_Uk3JonKVJwN%h?pPlwl^GzijCV`yy9@+zD_D^N)XK3aUWq*(EzE`IWMNtTg zqk4ugcj!+okT6|9^@f}1@#-KW&+kG!E1_RRJ8nE527Zz)s4)M4@fbqb;ZUUtgLwXP zu+WWe!AcG0{}`atxDh}n5GSI*{#Zj)V4~gt&r*#cq@cv6neGGd3dGnnQ8OMqYa5EKE1ef~kmJ9_|g=2j3ZB%YfH6QGtA zBo&4g0QWDgL7+(E4oZrX0pJgp*+86OX@TG;S6hHktX}^RYCHt|)r~m75d!#WF;V*# zD^prTVC;)XBv1^glZXfk)&9d7(u}H>`k#INY6&^|j(FDI8rQMCeNA|DhcAljUE^cO zfD@N-H!tE1e~HVZ-Fr>ep@sH8+~h(CYD~OI8FV{!n^hgO#&=g=U)P$>+F1^r$_Pa+ zRQ=NM952sGx80tiC(n|Ny{cPGuMICD;Mv$&)T}2@5)Gpu7;m6bz}FDLPV7O&kvSOtKVt@&r>_1MxK;3@-3^a|8r~v!m3z4@c zT}?y1f5$GWoZ33Us`AmUU{lwWhF^0*D7sNB=T3^(cVAsIu+9B(vjw-*70wzcy8Vgv z-1Q@qvzK;b4PFlTxN25Jm!GCsEhpNY+_Fs^+1eqRPa1^g92cP zkHHQCT)MG`cdY20JGj;0ESAYZ{Y2XWcV!Q?zCorn9D5r+B#F%aBLQDZDmWt6KCao$2=xq0P~Tn0P3?_q{T{ zOWbyXkhTz%d}}W(F9=*!>t-*^HxCLDkHCML*C=sq?3}9pTF!(7751qSg#f+)&b15? z1bL5t)6MsxdTM|u?62%qjo*0?LlkmUUt#c5xORwb1eRmuvxvxD&};sXk%rn*c2{b{4n{dj9wg@@VzWSNS_|k)8OFl3c^bB*9JAGtHT7tW@20AR zN@+i1QI^!yI*lzDZor@;CT;inTqyles&F{C6}a|zJ(|=qu0j!qTeJ36CLY+z%t+sh zbDj@*U>+P`t$mSOD=hwj%5T4R{JrOkE7dXOH*rb9FqiU&wZmu)<4#^?s?24o`HzO7 zEe>>thbot*!{;<2tkD8ul24>(6LU0EbXM*2P= zm;0l|RaMQS?GSAm2YZj`;`d$6jW0jtLcNZjZ+-GUa1xbpmLC$uJL}+NWU$X1Kl9MW zK|@Iy#SIFnYHO>`93JUk@?*@#Y>Tr9#&A@ua_ zd~Ir>zUg)`FAG9|1_8_HGHbPloXnD2q zu=k#4(uH!HcvnDbYwA0tM(<1S9(l3+?$bO)r3J>))JB!m@IC}igd{`(v|V!s#K6kY zR{cp#b1|$xj``5<-rm>lXf4Ti11=)&`gmTWXwRqDA(lZ9ZMDBCyjDV57hKM`8DJjEE(Gu= zUjsb(%ME^|^Y?>)5WE)t-bdtIvb-H5XNE99zl z##XqX-|ZRU=2Y?T;YUHGx&54Dz~8i|F#oM)(0`YIg?azC{QF-_Erc)JX~StHotXB* z1Tn0vcLnhx4;)^$>R^(WI{dlHD|Q)D>ln<;c7bdWe+5h}Ymb>eBsGvj92>}0yrh<& z#uL*dah0a<%lXoB*Pj>VVDmU@X{0ZvLgncd4pn;&Vnc=vs5v8vD(Rm;)F7t0NMLwP zKm;$30A%^Kuu3`}q8BLna%Q3owjisll!_m}!q%ea~ zbUUwyBlk5uTRNSkJ{lyEx9_GX=5B(SM%UGk};{XXvuC*ze`AI_-1F5W8T$wESihc} zpEsQE6=goFx@R3X`-$en>YH1j_^Xe}A1J!V#tYgV?iG*i)x7>T7jsebP$ZDkqfw~$ zwPrcLc<8EA>9IxiJvQuYFr@d)Gt1x?6pd=7N?f7W)I|T=%D0Uw{GTTsdCg~KUsR`x zUj6=s_XKfAc-tyVzM zBY79rq<+nLO$!}wP6?I;cO%coU%kwrf28Dm1M1Be)Pjb}0LS{pO68k)zs6CPcoLQv zWs+36Zl%#e16SMec~4Q7ecLb+fjQJ6l^iYE>F;B;DR~&xlvP%BY`XfR-EEjNSCjHQ zwc;&)`H8Xq-S^&Hdnl2G~<8 z$Q)viGJWWkC1~Hv84atKGpUGl-Y;%w~r6(tM$A z*J+-e^*+wIIpv4qvw?n#Cc4T3U5p*C5oPrup)EERBl4HLBY)UxP??5`zb;+>7}}&5 zDV+EuWwn#mC2moj7VEFm^~h1gN+pEnFy7J}`_gJLjdXqD`K*7AjCaJlUXZN)OnmBE_?xM{C=GU(9pE5a zAaH_jle0WPJNY93x6{DCPC63L?Hq7x5D4nalR!E3rjwp4b)GzB=*pjdpvZbb@}-UKH>OtXJWm%>Y|vtO|NI}T|*6dR+LN% ziIoH)1;*KLJ>&WI8K;v_X`vz1wvA+FyT8u!OZu_D9`EahG&hb@k!akVlC#bZ%qAp&7xUh4CSWkNe(^jo3fG0m8tV5q0w-*Sxq%e z0qNTLqpFS~qp7*3L$n79^t~QSd$eCC35Iq@_jSKPwU6I+L(d z_{y8)74P2^l0_1*QrlCI(}JJ8;1?9ig3i&KtI${oF`5vyAUFK*mCA-F-{zAv;dYga z`+NL?Pt^4QyY|IHs8Js9!Vlk@rC@aPFE=op))6_(VnGS^3B8;`4xjn*p(3C0SLM@K#Y2eMJUyK<@Xhvx;4e*M8J zlk_>8jB5%jMZ>-h0=kaC`vCk%2_R_gwn8HK`=ty0kbIH&c;Pds;MsWyp@djE6v0Mn zK!Agl2$FI)WF;W=1?TF8@(KS-eenr#|IZn02zShZ@=33lL^ z*x*9w&_B{JU64lm>utf-05;Y#NrQ{kl;_JG$;)NT=n>~EOJU_a?)Y%%Mx0d`@-vUE za9t8Pg~u;Zi%YNSno*{4r|b#DDFvbAEe|h;#x?FR+&Lo3MQUlKS>_mxuZeQcpbrd< zsR)PI$#an(%XlMCJI+_1U>#?qVb<8A!tTj)zl$MwN6YkHEqZ4zKO4I!GW43PNIlW- zw5!6SJ_eVf)bDDnX`i?qYB0_)UT1vrs=1!|wuxg)t(b(+)+^|R1j>JSF-VeNM+wbgZn=v3ATp^}*tW>_z%@QB?`-`tg(aOujaqgk_Yv*yiktOwy zrvjyS9#<#T=uy<$&Nweq8YFZ^#b$1`Dfo|(+u0Y=W{zQww<~k~y0Bf(GU+#AkQ+a& z{Wzxn!xux|&s`?XD;SzFlE!z9C)l%rIll4mXeYe1fM?z&-F&@`HHP%JDq1UP|B>Zd zv2lejoY^Ji!Jzy*d8f5~|3GRE78lw#{%^SYs%jgEaiXzgueOx?Glt$S=tj`IK3k0r zchHEH*k6uv8b9@E8};$XweG}U*n7!km-*_+!9X{$G4Y{9O&0VclvrFb@547LWBdy> zJR&fm^%c7S-GeWTv2QYP8yoCGh$h<F?gO{h7R;rW0iwPmfl0D17sW&z4$rl`kX!r5A|6@AX| zRJzcknIPxEFq#p-ERdT9+yYZn2;t3_Px}M`B~o~D&a32aat@pkZvRO*JVb?Q;b9QK z7BWDFMzRuMdR8X*39SnJWSRxJk0KzGQXopOfSP|+rOEzhubC=Pec<*1|LnrA zf%6Cp2~-Ad)*GW?V8AYPkQi_21MY+&VL_>U zoKLQHYvK0aGj?j9q)HCMZ$)=J&PiV1{k+4s_=B(ICCKQ(s?PH_I@|?}(_z#nNT>|e zi+C}5j-P+)4Y(4p9hu^|DNL~l_MtFneK>7Jns~g27#|<>^wz;J%Kd+L#dzzOfNBVw z;RYVUA=@}wl)#X!ugd@5fuRrRHHF}FiTy7+xf&|`5C_88l~xc< z@4xAhIp!QlEbZZFo#52AU%a}c+b%h3KpZz-2w|R)Cgd2Mlu06dnbt@x#kK<`6U8ia z*paz;9chKOl}_+Q)f6S4<~{2|N_8-tfzr2^@P%byccbVq)@>m?Qz~ofj*TuwaPXOt zlO$fGRqQKRq@`xA{OPDkAJBq+pU`TCR1-Uq9&6OVW+dDz%M%sPX3#(yfymgHS7z*9 z5@p64rsT}cN~_meJP{TB1=iQdGt8>@?j_)Msn9bm`R1Z+u9yyMtTDx-Gg9w0r9$b2 z$MGZ5W*SQRSkL3rv*_a|&AP&B(4dfB<=5y9XA*yCx#F1VnBh&ka~r4lYp=&(jy`Bc z**orm$7|o>QySOY6Sos77Ua~Nse^PUxkiPLSZ0qoY)rGzJAW5nVAw#0<+qy((Rk3y zcef($26NwgQpOjrj%@Ak+2jB5H`Gs8+V^3#xRf4!`y*YSGm4`A6C2TUu?nd}3v z=CNeO?2%K!6zl9^vq!(%n`PJBph&}1zcZN z^fGy|cm4$4(-N&UUo zaKAM16Rcri!xQ{H8nfuZYh-=bJ|Q zQ8f1)jEW}d9SW#&nw_dRt)_p71cdfQU+rw{YYy}_#V7i{UD~epHMz(BxwDKjm%csu zsfse<;QmT?+nSyDn(Z~UNw2G{PRYZB=Ye_d*-6hjtAa!dsJgXh*}i+ta+Po=NUdp| z=pU#>zQr8EY>qyyBnatKfA2aQ`=#UOp7rSfdSIDlP);da}h3QdAxu0ZwjEQTdFh2&-rTF8K}gVw6CfZkvTCOW^4+UO`U5 z+eHvQUU>U2C^pYXJ?xSCuAHoG|*-*sUe!{AJ5_1o+$`NI_q|qcdfq4;^4$mDO6)_iq+eS zk*dyM?rmmR*)j6lI`Ncmdqde~8B6#GYOo%_-G!j?G1&OlCW>Vc>VLbkR6)FP*+DDx zzcP!XW9`3?#}bv}<|9b_pu7MV-3HG6jnGDZ9yqM^T-|3Sv4OnoiNa4W;g6R}=#Eov zmvzr7S!Tj$-}@k98uR+FL_lAJD4D;fbWh=1A0JF+}d$(Y0Y92SZb(}?n!?4rzjixSDu zxm`J^CS!nBvRyg{VMGJ3C1xsLmVFkT71wB3+;AbY3LlJ{S7zic^T(4SQZAbS9HKog z-ZG`8EM5NgA8{P~!Y9vl`8f!=Ex!>zV$af!if!|?NY&BElZdH-92Y8C;Wfm!9wU@K zO=T;6iH=*CV`e^p=Ks}7NyMd;drc~5HauIb$ur2H13F-r);w-mNK z!P9TXt7UWX+vxEB>6v+9)@Ih#^LvzwpeM+`xOC%3v+G39lU4i>S5p^td0Ow(g#qY8 z%bxy;7#~wrW%=b<-$;gb+rl%NN~S*Ebr`~sqydsB#FJt4g6*fv&ye2%!|na6W_9wK z?h$ZN5)T;BlcjI;D?;`$x=W0Z%Dt%xi}>RA?8|yvobM_P^C}3Y)F*XVjJ>(u;h+9^ zXcO}A`Fyq1c$p!`wUG#6w%f3CIHAmhd0@E&i^RQ}G$etJi7LIgaE1@oJadABA2cuO zGlJMNmdY&1SS1!Cj>=`-vhiIjep{$~lgO(CggAnl*C_2MwxzcZBw+>cif%Fre19_v zH#oEazkHKX;JeKz++5AAgpi;LQ9s}Zu5|c3q7o7x=m|dh2Wz%fz-b4rxAtvDVYM3W zZ%H9xKm<62ZZbJ&FX2Ddq^@5m;f~jt~TUU>0mA3hRoJVABA?d`_j=lGH8|buMr&-$tLr%X6yz;l&nZ+{3%37~PF9_s-23|MfXMQwNVV0?t zKk!(J#H~bBXO3OwgtBcQ!Q4vk1~tQ`Ux9SPUJXb$09Tv{`um)z>}uVgHYjG z*!)Y^81JD{!9PZGGx!C00Mal2kP90WOL6}ol0ii-&EQ>r9tC0exJ^V=|1~Rb$kd;q zNMBlj$)MiQm~Zdb6L2^jt34WyP@0P78i0L={+SU1zC2O{c1L_M^$->QFlF9b(rq(JF8IV(->)*$y$hA{KypIj%t$2f70DU3&421zimZWvP#!TcqZLv`#S(|KV*y2(#CLLh&4cEc&cwVkw1XLpC4& z*677X@xCdN1IM?RXE=%?CpbdbNP&rYp%==Oj8bRW^Ae12V>eHppd+JO?3ged+PO-X)Fy~;U6e38*Y^z~t+cMM}}W{+bJ-X6_O zr!!70Z~gOA>1cuJbTdXwVQW?`*{E-qDQEjX)NuFU+`oHDsc`w9ypxCTzC^X%pmn=&*7#|x8#f%mQNkDlcNeM2Y_kG}OPycL=glNCdy zyx^@Cb6(b-&Y9}+Qo{alRVHgLVuyZt_Lb;F6)P37i>(o4Xwz$Ia;frL+bqM|i;%(R zIh477Z0za64-DKJO)1l~i%+CY$Jr(?{I5qZ8 zA?Yd8q6 zTmovaMi`#(a6S4%TeA^=@v##YpinYY-^>25Pu_p7oj2=w_Ucq1 z*frpi)|_gYR!|H|WKQKr8Hirm^Wf z1M(RSShXVtCJZAFQ3v+01tdp-j5Hc7Fc*Z%eeDo>p!aY?ZA<}0;z;eLbDrp{VDt9a z{CpMe#b?umiQ6eNWJx%zIGgqn2DR+=!dK_uQ82}Ep#&w(@^$}cu%wW!` zzE@jA3?8kP_>Ab8D6dA>=I;ud)KqXqJbR-xB@)~XC%J;M@Rcz*NuZ>)4#pM!i%p~+ITBb*>uAv)mU zs&D051ruoRZeEsw$yT_zz;EeCg(yQdOIYB!at5gPN1-lj zF9JH40FYyQQtrVZ#C<$~4&>OH@4CF2l6i5P?X{|emtW!8UMEm~ZAzA&Nc;}^R1CE^ zZu(Ttw_30cZq(S8p>fW=bBA3u8HYw1wEK`$eDU5VHEBQLxi-(BxI((8~D)c|9`e(N36?&}lr>HNza}jEA3)8{eOD zwuz6sOn87?>9*(W!+`tmmB7;&z(ki!IiE$`Lt4Do3(3%Xlcur5%_&LkvdQitB$S4RGjv{cYiky?RPPo zz8|ybkeG>#F~J(Lp!&sfqs8p=PRgnDR03z=!jQM-2lcmu)7P9aN~2`ciqkOT8dfbl zt5szU5*_`El2i=IbETvrQKsI!ajc)|8t$05cstt}XcgfFLK2?wRC#13c}1afZk_L* ze1;}TPnT{pSg!0bkwZqqYjpsbSc9UB7lY%8KzbI}an9s&XWJz zn2SyNe`gPA@&CPV$ag`6US>$sDV_36r)_~%v{$M84}bd=c8nIoTiaI}FxX`bp`ez_ z_!f*|F%n8bx!taQ>aG(RkaK(QT1lK`Ia|-?v?wY}>HUM1SJm(pG079va zASkeJ6<{6Y)4x=nSwHB$0=qXn&k&m7byRxF80b=e)ioI(Ej;n@B$j{ke0}+x^5{v zvA3D)!b&=7(XQ&NG4ovC$ZPf9<4GN9D?XrCKd-I=omsV@Gs{)Ox3})%UuPD`lp3b9 z{HHT(Fe@q`wE9tx&hq9}l!y8s=pcjUyI+m892TE2bcKV`Z%uTgVf1fD!LYFskgin3 zL1egrOdLD6vVV{%{5MH@IRwFjduR7RVG_;~0_EfXPf3VZ@PA4|YJhp{Z?BfW*mX-( zA`;DBxOOVMSBvPDJmjA2pAh@5i$zp=X__W&nWv(86fZuK^)|nBpkq*+lBXpZdKppC zHV20CEhSOLqfv^JaM0$NUZ5T0kRc+;3(_J(hbU9Sv`_tIC7VQ1Sd|@xAzr7$vxSKK zj2G+$LxejB)>#N*%nZUjsG4sLT4c&##w2&MFqG%TIBejKAC~Ct_G#X5)naKuSlsGh7d1LMKxJxwk`kouF`Xzp+IY?JvkdthA zq&{(qVVk=57-@;qCo1>)(H}7zw8ZbHmU4J^(w@$TmA>_tbVlatYLwQlXX$`GHoEE> zrCFgOlAsn*_N@kjT$BZCYoP}}8Mslnph%U@aZ032iKAx<8Mvse#b;6itXRR6%yfz* z%&H|D=xX>cUQe+#<7cgcN!VZdk(TQC-t}g?-JMk{uTXVQFP0Zr;#p~q>E%QMeVim_ zuvAP%j_!X+8ZH-0Zk=t^tRfMsP8$`)Ljyczn0dCW9|x3#4|h~qMO^&QJwx?*ph=rA z%0FhhAbF7XlL(K^=s2BmJZ;wOzNhFxnfSe`pR0PmK&}L~7GNoZtfO}#zh3O2?vDJe z73KX05-Osps(zJ>wi@EdMlH|0sc&2smCp@DdMR+u%=}_jn^G4XpV40}1+YEo+R1L_ zm+9;xPlzi)*b;xKXqKbZoAqJq#1+cjGqJSV&JxXDa6e+p-*U%%9!F5ODaS`pbWggz zg!|=Ks=3!e$6GF=gv6(B1I7jo&c~N`2qCjO`5cg0vpdi`%Q-hipDG^@Q>#n%+IZKy z+3yx!fB%uIpwO{XbQbFP!!Up>#Cxn$!uDx+`TJS5REi`DyDv|h=u!p*$u);@Tcf-l zf2;Yr>-eF8N+M7X``Vq@MNGveuR)d#)!hv(d!_%gZ(TdZ`yI|xEsAe!Yq+$3@IMEe zxMR0{5=eafa86)TSj;={`)=eb%v!+sEI$vBUgv}Xoh)3~ zJ99)#=xgGN`ZI?Vikqg=%A2NA)+S9JdS%)nU!Y7bN{4QyRTm?i6(SBvIiJ`dNC8Ej znr1O|7SR~C{_p@QCZQb0qppEX3RDvA3FJwoB689e&{TT#ahKtPONDtvhZ>D-C6Vr{ zeP5t7dr|kJS)`%)b>77b4@7rewGdBkv9VWKhOqyD7icT(>T1?Ct!xtfDMV+Y4f)`q zM%Z}u@+p>yKjQI7(D1F5QpW#lSGRqozyg3L`LCbjXz`zR3545z+(#3@i@S;1`FU@q zgNY`A!w5Gj690{oqcLoC5-hpV2r}!qu_&1T1ylc1po0~h2M|6`=m+z{K+gR=us-$7 z?TLT^`_c(fMFQ{rC2YipMsj0E`{lnT?rV-5uvW1Bj9qb*s^`7;JsXXBrU;k+pJi## z*EH*5SU|-G@@Pr$o;k_to8hzN<>L5HBj#UmRWEnfy?t%j;#MKRvhUC}l&tP+x3GLC zS+3n>FtK@$*WVCFV?8|TskM4HcVsYbO}}=8a^Yp@?gZbu323Wuy?R-;Qsm`u7nh^x zO{js3Vg{^LuT0&?&RvuXec|Vo-v@lTvtHmsKY7qB8U*{q3#wfCIMxJSW^|2yO>5dNlv)J;I z_`h6v4d>Ygk2Dq<*CLm9uC#n5+DEID42SU&pTp^wR2m|@dvi=b^L6OHnG`NT^H%iu zs$qf;c#%Aa%=FzH=&jmT@ zjnl4z6H;_UB3?g#c0MGBixBBs4>VL*eU{0Rm`aasep@;f{AO_aL}}@>tZ73BPpMSt z@qPpE+?GqxeFtz>OY)?93 z*my_^@uDOtAoI}2*RdQ6$vzy0M zFQYEtuGo8qB+4z>0fOllX$mnGlFL)N`OUW9ltzq+l7AX}RAhxD11)$$NDqnwsx;G> z*+?M6L0XMI?>xH9NMrJnzAo<=jjl>LIiv%{A5|3#9oxX-l}&f@cjbAuB_{?tLr>}M zyksrK&<)HnCQhWEv20QIEQDC5krEM?MjD_Lb=?byM=%GC9$bTkpS`Y&zD6a2j?-Ch zL*mVv$HTYxIqnGuCeA_Iay&506H{U^5)yZ`3Az=D?L(AOn~W5B0_70XpvX zg2`ci{@eDt)&;Nz-tq-dGJFlu1Rl1=B9W%_)uO|o{UF$dmkd}zQTIl092EI6QQ)1! zkudVtAg0~V9YkY%z~g23-?+a>!Sp@vt4AavY64&XV|a02yxdJ@jO+^Y0oHy@K@uT; zIsJqyY@2B5wHxctjz9(9POnRu_Apr0=ls+C)~rgbv3fP3mRK6xfg(CfPIuQOpZ58@ zmxEx&Bqwk^PC)zUbbyvC>=T9t#5>sJ7WN}n!Nx#u!V|EKL~@7a zRWfT}6&&i*$pCx*O&S*UBe-;HBZ1qf{@q7lk<1aejey=ey!ASD{r_wP3fv|z>6r4n0q8StkZ}D-*`k_+Y%w5c#^Ov9C-^^Wr zvQf_9CGI6z0=E@>s9HA4zy}OfFZWEp@@OmyMR!V*9>r|eJ0J5UYk0D%bK>fwV%OVn zSqLAzxY7u?YR#(sYb!?FfdaZgc=vT<>HJ%vuKYU_m1uai26Tfp66~i)Bzew_!G5)2K;q2po3rAKK76pG@eB)}=d$%82hJOfdIbdHP7-|B`+4_5LfeSa1 zpjO-90yra)VSJOId5-@^9+derI7&f=1laN~-*UkYa6_j0&|wlYU`7Va&C|i(0-VLS z#W?6V?rUo7u;Y-p9=IXvE;lBEfHrI)sK|Z%T5Q?j-)F-vIrihp42skz6r$&KQF|Hl zee~UYKl|FitdoLpeh4<#L6Q$-7JBX>6gd82!y^)d5!*bfoc=D2o~iQ7+uM+AKSr~f zM7x`&-n6@Ab=uDNQQwcFbk%OdKZ4x$C-YT*SYBPU>^0PpFGtB_J6PdfJSTkI<2*L; z*+|6tE4*2gvdt=%urZ{r&$#~t`NS&twtKaD_y6_=9|HopBNaSg&VLb;@f<37%GVzR zFqggC)C!WIFzh4&!Uz@mf1;#qeHC{CK(Tnn792J9#ea=XH)%OK6~d~OEQ9E|Sf)az z=vVFiC=L2TEPGY->HAdt3T4Xslf*%9Kkf{xr~2MQWSHfW?0iG*mW6$|MYrD!RX z(~&C46_9bX>B>p44F#?4l@JA^QBdc`r8A9rz7A*hSIW2>!A`bV#2r3-&y-%PL5_2# zO&<*{(f1Qy{Wtm%gqg+{`3Q3O%zl-s8+#LQ@`xSDy^ca-Gy9Z? zjotX+pejW(lc^rK;B%Im`{U@KTft{_sXD0D@&jRVYthJjV|CZp3KDK!iHUjm?|ckT z;_Ipeu8ZMX22E`7^|1ngC#dgda0@T@5yRJ)m2h@OXiW77v;~|N4d}*lL%fOc=b%p= zYXMD~{6abCWUKZ&g1;=rR(wl0*s@W_!tDBL5uy=Wkql6O%csX^KImO2Us~PbwRSzh z*+bk@5@szHRM2@9+)~ElT9NslYq{5&W)_iY*!9`6Fr(g_KC6;jEc`8f#<8=SjC1`cOH$H}~CGt$eLD1RZ=I-X&|J%e34kCD>B&Fbj z6ZU-{o`qFIQ~};H&~`b1c*7_^LQrAj@8PkB5M0vN7{+%5Fa!=4;Nbz>6(%t8FW^Ce zYipX$gYiFp7*Om4?PmWdHlQR9dp-YE`T9Lqxa_G#Y9Wo^^C0RS^)oj9z^urna=!ZH zc|*~=t8x9HWG^&$atKQHGveyrLTb@+Q>%^zh?esH%J_E&JJc&Lr#?S3dp#Ei`fR!qxkfkx3{}1c}LDE~)#j&z*`B$zt z{&o|XKpwzH+u_xEA&`HCVA4bR{wJ9NZ)20Wr1k){x{-YV^?ifX+5la^XsErW1{gP#IXDF7jen+L%V#4-Ye=K5e`$!w?>RSE_|K zQ!bZ^!0>okNlBA2vy_k-mO`0T&_zEsg}U9yKM;`~?ZB*~mrLnpBYIS(xKu%9){PX3 z&>N|gs?f(3dWG}ShBA}I)$j}b`>{Pj&QISDI9z`)9|db1(Re>L%XvN-vlFuk>l^BO z0nI)`6$tBfTvl@MluOD}S$Eg6X!%q0o8aWpdawAiF8!?Tg+k-Om<|19aVln!QMO@+qKyoNZy#2;&QXf;R@Xfo;DfmEW)X&vd(}u zG-Q6o@4mM`eEj9hPp^KNaVATmvhf^^EHB}K!c>H=%7H`Qhr4JpA`Sz(4l<_EQX_O# zT%%S-78!16u8j%06!(m$N?z*m+l%p1v5P;M6YGp^+#Bm1W=6!%U-dpE9plZsuZmtN z_NYpvxB^{tL-SW}`{6J5PF17v)JC#=Xutq(RpN^uqd0jajEAU zSa3Ifl^w1tvej88N|BbX&E&oa^*!oJ=HDsH(E08|yh*kwEdNu=K-ZRpqL+r`nP~}~ z^7@dQQU4qL#g0J=+$=+_x$aJ`*>J*rjL~{i)Hc?#c*&FLhA+vinbeB;OXDv@>7cDw zO`ZFJfwV7&9eD%Vc3>8(6g+<__)cZtyBm4ExeE)hk-NW8JQ?A8IuA@~*iyY*p#8)5Wr!tua2{i`7#0WpC)Zt?cUR zY5dt^*1}Y4lT}pKlb)IAb+QfaEMc-DLm)}DH~WJVn??;ZDC-JnT&aq%GHVS|4^oj( z_*0W^D47uGip7QCJNv86VychAEDYkX!A%632GgUU>Up$$Drn8HuSGBKo~CGC~M!zoCRG^-%KAB!+*xLL34WKP&H_V3v0bM25Q z$srSshm`_DeGNpV_S3vP%Uj?1RHu-sRa_hTXjycp@f1T@8%gGWO7xyF;7%U!MXJJH zfXL3ydb|MeVOT;Tx4S3YNo3JvAv0WXxQ!WqfWa#(j84tTUfMH$FvkKHD0M5-5}NTN zqJcr~U`K&I`UN;eZF{?)@{HAcYSg43lx0p&aqd7#0Ab%$6nZ}XuU};3Z#U87cTh1Z z;aiYOtbSdb5Y9{%ZsQaUFdiyLe(Y z_-G&@tk{|TO7T6rTcf`^mTDxFssW$ygxEVrTHZ=!DBV2}5=m|DV|_j~y~mcw)f`<~ zAfWu_R3!PMaqX$z$!J|7yzN+==^4xrxl2SiN`g+Yn3Bi(<@WowM6)bt`uVQ7MaS5L z)Bv;<`;Rb1qFKX0e*Ar@=Qi^}&2{HQsJF#OI`k`GmCjX|p-);od@h&_pC<+Lgh~z7 zEMcJePFD8Vs|{-rc)1$tZrGd=!x+%fny?pc~gMyyIVN z>h3V!s>n*wW$1thdoOSq{%!p0JdM$Z3SZ<(q6RyYj#7yw$u|aV5;m0ep(}@F`Zbfh zVw+o)5j}T`K+`K%>{O%#S5(GO>QH;UL$f&590qRrCX+g(6o-t;eb{!@o}yTq}#^y`h7g+#VRKNahEak(Ti{9BTV~u zioHK31;Ndl($ixC$u=<6S_QHmS}Hf>Tpg(x0y6T*;o zTS%a)-BMCg_KHfu3inQL#F78h`SU-qPp8q)m=U{5FE%YZ}(Kw4a4g;NWd7Mcu zo%N2RY{9jwrvZ{rx_%YW%hL~$ZD~^!@Ngj1aDZTSIMrG8TZre>Q@mK+Sd=QG*Ue;1 z&PQ;)*nZuAuMpcGUbg={&p&x$5dFZvC?KYM+2g;+9R7sHe=Xl1@>!GZ z7qkgpI|0#&1nYv9^b(}_!wky2yL?Y6;V*ETR0dZQvDkXr)v*3*N~40#+jR39vxC;N z360dmB3VBUg53@30Z|ShajZZX?!)}PKNxPj#-jPXIfuii@Z8>CA%8)}?qwy-+sgI+ zDI%yIcEq_C3Ik!d%il4ZAOAPXZdR|u`dfp;A5>x~2$h&^4XXbKE#DU0%BJ71Kg$Pt z#;q;TZv@1b3G?UP|4t%6aQ+qI|AXK*wKx4w7GeJb(ci9~o%IjlEffb2Xz@T51^A%2 zms!%r)y*9QtmFP~m#?qqhACASDAZLz;$_x1>(M1{&jSGtfd_>P-Z>zMXo_kk$9`?y z9|CwCeyQ^<;Z)n~z2-$bsDz{%uCCTwudi#X73^2^n2($r*km*N!g2u@8}t1Xch(>- z;aNgV8$ND{iOK?i=N5*ydKb0?!f%h6*;B+(k;ctS)3Qq1nGe`e{GzP#?ks9EC)`jd zkwf;ANoP4FZDI0><=QAt@)lhFpkRd?YcLYAP<*78U_ENUl}}FJ3&EnGy{}VuRM*F_ zS0h)#kS91r4NP=8;>ktR@ykwJFPuRQ-#gw#5T3d zSJw?&{L6Iavx;tfSh%KcJnndkjV@zL6rMGwDLrTc8U|kRue!l`nNGfyF?L*C#v5Z% zo5pN1@@=C$X!(p$#RY2+vkLi60i z3t7v#Vk!Os%8j+(Z0yUgc)6A!+A3aazYSwAj)N3duIR#+7gs4Z%F4~Mb_wjRIm?H! zRpSi{v+O@E#iVey4r3?R{9I_@wMM>rHd}dd^Tg^hu}|@LE1N#awEtKdqv(o!{cINR z3cvzb_#@QB!8g`^mFScl$cz(>^^YIn#2diYW0_y@{$<`pF`OyLy;M{C4Lwob@pH}6 z!$dYk6JjMaW=a-j-(C#c3RNGsp%#>R7UG6_PQ3%0KL+UW6e5(4)!;&!hA)wbcx}zH zFv$mFw*HK)9jV~zt2s1lQpg@DHx&iUbK6K(7rQr&TkO)6X6i?1G?}(G(eCPL$Z^`I zjD9aqe_N&kns_j-H7hXn;j8UvsQqkiD!{9b*40A@svfq|){;}zSF3Yc6D+K=+jc1{ zeyTpo2jx*-*tRDM$?(Dj!0)mm|}FG#0XeKu3WXf!b*a7QY^GU?x`|YFLl3iIx*himBnTAL|NYXV%4O$F~7`nooI;Wj`!o zDw#^Kx~g$RS0~4PD=|j5ORrFm)$G?jRBw&$X+)1;W7L;zl&xW7w3kiWiQ3=M?^D*= zQL`Q)PN~3Z7FAsi2x29$CP}((}xgxuG*t zLrAHw-c@S{Mtn_+$@$_UD*iD~Q+M=J+aUOX5WHo!|+obFM+OhQfcy#(0 z8hUOd*6cUegG77uAoLDy$pi zGHX!-XJ@~(3k0t`2vw3~SC-l}VBM22;n=abK@9Vc+*^71yZp+c{G6b||f7Tqw>6)Sn-q2x4KQZBccUo*Mz1DH(S&l9_ zo8#!Ly)lA#Cc)JHjULSD{`M_)#3R+-Yx*GiNE8uc0U8LPdeKciF1W!6%%W3pJs6%; zvEvAXDg5STIjQv|p6Q3n%tJYwGUek$WdVHzBYjk`t`Cbyr|K07Cq2gzyg9?9mT)oB zKM~Jb;kcgmwt5_2I6msZ7Hy2jdCVAK4-d6eMb+1VR|vTy4nQxEn){SBV6TWK;7(TR z6LN*2sy7MnI;xakJ`?RWFz^(u-*lkq>*y%FdQqKWVqrCXM-(ss3_E?|ayxXYEB>|I!W9gMiq2 z$y?s9YYbV1$xxx&L*zE)r_>>)8ua;I+%DGdr4BYrhB- zZMr^ieIJ9Psfhdf(7qw<62n2&lZ)OgC7!qo@L5ptL!K26W)k3?|Bgh?<#Rt4Z6C`q zL=X3qSYee`qLXM?d^HFL`AbjzQBvV?@<>Jo&Vp{e2Qoi62jLpSQ6Mf21k;&Wr;25N zQz_ELh;tref>tc|Op<4cv6A-mP#nzwR2P-~a)%iLnJK(xe$&7T zV90iNbwHOiq|W;~ z?wmB-(-Dghf$yrCo(~Znr=M>6fENEylbreW`#lJ1ol~s*R+q8vyh+`|`L&>ViYtHJws;4U2w;puU#^kA`1EiV^xO z+M9U0ZdF7j%>aesA9Rbx2`f=Whxv~B`+L0(5$d;a5ocNs>3os4Q@ukMyrbN3uUiwC zX5T)c27FAqA2G==&yom3cxq3eFTcT%T!6xfpx8PH%Q_uQ777EFevn)E^b5d;5S?~& zb^U24Xp95ZiNjC5=ah#1V4n+x6gun z&%;wjo0j10m?-VdiwPR12M)$d@JwEgkRsI<@jGIT%)hN#qAtpQV}y1jxFV?WX#%%4 zmh0}S;#znMlI$GYh&)o z)(L~G-MKU?o0Hfdxo>HmIe?pmEi9_ef#M@XQY)~ZC+X&0CUTcjVN;rR(P(HpZbHcs z@k@`P;x?MMo0}~Nn{h9;h#}>t(@w%L!O6J<9<6F)*!9QUlZ!52zB~iOhl*gCP(Av_ zuqmee=EKkjgKzpWL%y0)apG23d(KfBd{Y!XOTxPm5G=$uc0J%iy_r_BBoTAMudwqsEa{CDWd8Dijte1RtZ$}nD+_Wa=NE-&%lITast@G(6S6) z>d`{D#t^f1oTV1YB$PKHV3^mR#C$||tRXWP*|qW$c`ilapeKoM!AsTf>S;f(q%3Df zXhlQImQpmrtu{*ALj&8IgDn(=bu17CW|DB7DT3c57jgACP6Pm9nH&j_{-{a0{&73U zL86=}cL+tlvL!FSY1qxt{!nw}xzf3}h4z9U5EQg0OZ=&<#!#&hBAb>Y?&7#BGZT>$ z;&zf@RSB;eF6|AA{$Z80>=}uAdISc#=>v}_bEKf-Fub9JWWp1|uJ9zSpxRl(N<#|U zjn`>eR4N5P9peRn@Mb0ILxpuYMv6^yC3Sof;$}Y0?Oc6JfccRO9{pQ4`gp;o;J!75 zDxvi#CjjEeCkTr)R(EH|y(qzm^b;Zf{DY@1$=8i^KSJIQvLoI_Sj4olF~~zuJP@(6 zWn+{-`cxqH#)H(u^S}_kf-y!p$q>kCPGy3EK3?zvVNgcs*fn+(;%i@UcaDFO*L*zm@uj!(^hI|5N>HZyQmj4SjLk~BkXBNrlI@%PLkm8`= zQ%x{EXHV+!@jfq!ac{jqFx#@N;0s)?Jif_vy*%POH6q-kvD#wgaAH!*YF{;O3V(C( zCxmzNdscTI04CX4|MGFzcOw1|Mc-!_jenRhrf6gY?XZV4?ZPBM9g#WTV@ za>hQk*Oe9K?b*p95R&zz$MM#q5&l_=k-=V&)hG$uP(QEc0C+$G zSb^pE(vOoNI3BomF@@uK2}Nzbs)D&ZqP4Suv;XT*7IB74e;1rQl|Oj-I!cZPnq zQ=bwV>h$K~`ujz@;#6ph+dnjW4q1a6P*gOCsZcYIiBKKbl2N^J=Tu^4Rj-lg_`34= ztn=>a({YS*Gf-(Xb76ZQ*py#(C1NVs71*3P{&d#`e08e-<=T&RM?3D3u5F6(Zlu+; zbFu4GM{!ZNJJDgKghGrer>Kbe4m1E{P*MczeJ={<*okd;EdFVKsxTA5yw+3%=9!jJ`1eCEa!UQb@?eD;1!NcCE0{uv_oR)1VW)1d!w@eFvV>eRB>4@pN6 zsBit&urovjDZmnDl(%s8W$uubH{d*x~0D zTwY|8w@A9^bgz0>*fxZs zgd7vNN_D8ozyXjHYFc*TXfH%F{hZVy{mdxiZ08DWTR)LgHJf+}7swr*=Kp54Sf7g{ zCA9jwFa5*J(MjMP>9e+{!`}%^5Ve#KB7O5E0@Mu`2-Ac%3{4FrAwocD#utM+1%XNb z;wOjX-~^G5fC$O~tStY*?y$13{Wn+QxSpL8{%GB6AV31(?v8nPYi6h=CAH0pYielH z?c(Yd7NtOV-xSZidAj@dr1#4}0I`oHD205DaiDE2vHVvBvB8=#mUNzvJT#jzS=4tl zwqkj5(@raVRs>Odn#Az0{Sn51TI|Ind06JbbW_n~olLkYG5beSHK;|1Ba@<9EH<=f zN$LKg((&aC8CvJ6`waEop>$(agzQqvl)$j%22-|F%UnygWXs%1bHYM%q!@8y%^=q! zP%9-Z5mx#0JywJNYIUTLKPo;x6f8}Q3Y+|NuH8$S2g6BKkTRgf<5bNs8+M zMw*ns*X=EWTZo)NC>{Y&1H;3)#LiFfsf^@C2PZ^{K6K4HSZu@@XSW`1hWnwvtCkjYv5u#dC7khtLFgPW=(Ed$rL(*~l zO9m8WV+{S#*ajQPDT=SGtu(me;b2CvXqhEJC2{f?0ouV*A{f~KZR=gZTj8uri8uw4 ztSHW~@sObIF=&V0GT4u@VVI~QQ&0}7AK8o%GK0HYAR2<%Fh4LcrXGBO%U96hVUeQ= z-@*vVgWHRY0&il>S2M+E__oO1D@-6Bq4Qz6fvtDbOFY4?hdw-E+DQ~{+20~7fBa!Q zp-0C=$mPZ8{e^l5aJS^Ut}Ez(`+n)@&)fMXwJfU!Yn*tsd*tcU?A_XIdAAsKHE-Iu z&e1upxhZr>P-!=@&|EQaW7$%d&NbW0o(av=I}2pa%A0f>9J*BNeos#+g_h0@Z4A#5 z;@W{Sb7_8T`d}hViu`tB1f88DS(7u*sK|1SmMy$3s7PuCz$pbQp$ig~566=3sVkPQ znOWWxi%;?$!VUkV7ovXt5lbrRgNAgWYY~ZH@!2#IDN&-*rh1wS{)L+_qK$eu#~8T- zgOM@joFU`+{3$@2;Z*lTNV7iN1_&p&(uGGdq3Nb=n=Glg;_NA8ba68!x8cD=ZC#s% zVG1@;fKJ>F5Fl=+BX-Btnnq0}sGKK6J_Zgpwr`f%iOjFU$YMGM_kPigR@2(L9d&7P zvVDCpkUNA+*h`~K`~7KX#-!Nj$Th!8*X`4fkNHw?jFW*9qKOby@^s~dhvsaDoy{@> z2(iMU0;8jBqZh2@bhCL0FLe3WSWLcTQv#9|!7=4GfPM@Z{oCV!gW0KVkes9Hm%TM! zPuKICa_94GzkxC8%6E7bbHb_FRMdqJQks$*(<-aX9Vkx@J=7EVNeC|Zn%I(t=pj}1-JaU< zB_pxI0l_3BG>Fwy@s8JTB=Lq%D&9Ww7GHFKOGrEWYlxON1X@6E>Q(%nr|YEbYu39x zvxKo;5RSowI?Zp??V+>U1PD^1vp!H z2H|R&TelSq*o(!%zi<}?py$=Ut_6B)E@`R@Lj&L+c{RYr8MYE+Rn461Aov;&vr9!2 zRf*B?fackK@J%J{?XAR~)vOaU7~A$jqr|kV^c^R{5*+sHaVtcS-|Ay&8QgqowcbhK z-lR2x`IKM%e<=FpG(lsXt=_b=JzyVD4VM-CyxW0Hn;4R@n>z+CGYqED(e=V{6H^Wl z{{X;xfD~G%wY{&FahEGd7FGU6RR)Xg-iB&8%<37lfIKAA3|yR{^5Cjj$yY zkx0mQl~C>=D>FuW0=nkr%StJKBR|~4atB<)^ZAAwB|r9J_*<{qfkF>86LBdFBW34w za+{jt?=f_-aw42z`DCI~N0bm+01QSEnM1<$`&|5yv5;jcNJx~Xl#SkZDPc(B#RMc$@_y9Lh z&>>N40x?XgsWin}==`O#Otf9HBQ?qBNkvc;wBRx>ny07VT$;O2@ujyxmtJbgl%4oF z)e+a}MeUTJ4q0K)&^gLZ-w6CO$6AWqf9G}eYfUPP`N*lRCu3eFLl~-dkLLG7Pk_2a zRdbX6?E-xNUwxA2buV^I!ha8vO5TA%X_sMo*5ev5GV*a@{J#0u_S?!} z`{sDwx#fw|zT)pY`WLpy@3*$HD%eJxVyZm=gT_F7thDvJZ3K|lLt<2NeF-fY`LU{Kw;w-z(ED& z&M5Wb@xGI_Lub|g)LW~+&d1e@DMRMK?!-qgeSv1aT#~>(4cLWBX<4}U!2RGP}xukm# zb~fl*j4f$&U-ZSA6W43Gy3iI#{KStFQxj}jTXpH8(|*u zeoc5JjK#bBoO;xUJ(M3SSi|xz~+0i=Fk+b{-uVpX4u-E!)l3GE%bji;2lW8us@sWC79E&4l zd!-#VWUqnm3z>l5hK@ILB!eux0y7 zI#SpxLM_?|)VS|NyMLe8PcLE=C}j;%3f%2tDg7B$VrRJyh$U%ydR8&o6X>}yd>^pjjN>HqBH^$!D!l254!hvo{CegA z*mwu^gonLw%!5IZq>lT~l23lR)K_ zT^p4U&a2NYR@hHX69_0XJCPuEJjIP7f~>8N_G58(5?lHeAeAFXRNYpe*K8>612-cw zoI$U%WblcJ>&IpR7x8V$PGa9KQkykkt~LJ1IklS-DcxkBM)7l|;S`f?GeD5>JuqWq zO$cJ*j^Jk>rU%ZQZWph@P@#<3C%hiAJ;Mj4VNUsv}dEi>v-5_hb=vaz}kMW$#PDFy;m}JI#*UH`3-$Sc27L z7Ky1EGIq8LOE&rIAsBJ|YM9PTSRq%ZYs!II=nyqs_&K4Pnt#14vMy4RGH8ydo#Hr? zk&v?Pj8j3BcCI!QTja(|G%wi*IB!_*kQM6avC`_|nX6d4jpPxJlytOavHckQoo*4i zc(_b#RFz#aYs4h^9I4$N#xe8eZr3t9?um4|WpE+^zP`BV6XGcTneIE=7p@P5Dl=8_ z{GoygR-h8EgUQK?J~B`&;dS(F*C83r{2r)vM!bVd+q8ou&GX2RF8}p2Ntwml>-F;K37H2b`78YL?m|BhXpJ zi4!cIU(nW7+k{-Nk$`md2G6~_vPfIHMroInU_?)09CzUm;TI@4HUKAU22+GQoP_zM z2f%SHnpW12QtA%pF{nIbqmmQ}G%9QbW713b@#Ig&U>9Qn+Wx_>`ba~wCTy9aVUz=F znAD+%h{)deM1*jtXwAqi*tQa<@igqbiL9GTKVLGZ5yCBPk4$ah` zMV;DGKsDQmiwC=WcVDMqYBOIEBfORG;n(vB+XZdQp*pZ=1HatuDR5La;_q|m4856(hUX>YKV~Dmxl$9ZPDEAw3 zH&WRdGNZN_bMZW7Y)M$x^k(bZ)(?9+YmS*Svl3k^L9JD8OBE(G(=QvLBuT=mH6jzW zX-V(=;d-vZ$35CG0%~Qjt=dQ3%scN<64$b+?niKbCxClvEma4ZMj5A8xwvORWk(1H z#bf#P3t^*%At$WdrJc=Js9X7GJm&ocbUx4F@fzijxAL*OuF0oD{dX2C6k5*@Y$AGt z3IM8~le9GKX*}7GO>ztvQ{YPtv&{>|uK{Pcx=?si-&!(e3r_E0U&lpiny`Rt+-~G& z6P_HgjViP`PfJl_lGm516S;Bs&HLvFIIl|&10A#yVFy_EsRnfFo5D)IYJQwUx92hG zoh{W0R~@~pT?WLQ-}323!0{xDIRJ*^$#nJ zh#OK*^AH*IF$BUa z*my}OOHyZ+z5`B{bb?Wryz-SuXestiGJKL?o=<~PojLx_>j3jaBp%Ord|gB!VrOAP$_CKjuN_Pp`R0Av zWM+*|XnRE_kB(niGO9<_VPw}cHU*bhag&_gi)`(V8n9E77Q-z@IdKD_wj0<&-uD78 z@7=~n$``(m1qpr)f#YL)6!eq&>zVmf z6&}tj_|R$x`b=nI&zomb3dF$_95XatQ|b2r#1ktptPE)LyiYh)_P5&6DajLW^i}&3 z&6YkV(i9qJm0WELpR4QemriT<2uf_xT!)?%h0z1V_y&BL(oO)iWI?|Mq|sJXqc03U zC>xvUW5>~;1p2fCYTxUOS7N_jzsf;I#@(uua`5zjkY@~0h2v_ZQ}z+>f6>(TmxQf` zA%%du*;0ii%b?OZCH-NAG>6Xb5JpkPFHrW46bZ9*vIX6sqkhe*9I{YvIH2BDC66|F zUHJ2FSx6Q?D{n>sszeMscNB9ExF@xHrddg-3B1@qGm6}v5=_~5IQV z4}Ydt3^>EMZyH_@l>o^4 zTe3HJ3rF*`VmK7w3M(`=1Q#3dh80>A`~P$qTtIMgSZ1Iv8#EoLK(v?*`YXuINU=jp z0WS97dq2a-{Yaq?qEjZE>*C(z9djpo%^UdAWy6%%=QA zA0!!A8|O6qYqfAw28L@bjTNTvTkf&SzAS0_!3f5{17TW zM)Pmd5y$piUPq@DezigDy#ad(=nV}=Kn2rce&Wr%#gN=@nE)PgfT#z#xPcg)(4zmh zE9c??2A4oH0W&$FX#uQU9RF2kJFYeCy2FLp{!H&ok%CIa#ndva`)Ow}!LsO^{J=0c zI_+n(&kZdXgCwu1R_4^{V8AKhQB1j8Nr?3u#F_X6TuJVrd?8*L<9V8Y0g z9;?ZhMULPyCI||^`FbTnCdgyBsxwU&ex7_^05o=heW8NAT}F{a)_IoN^zF;mTQqHK zEHBPB8=3y(*RTX;(Y8SJ`_mU>r4F!n|X??WpV*id@AZ=*~eDZ2GMx z(E#S+O!J;lk;VGEiK*F?D*8P$4)jt=+MB=F4eKw*XJ3ByGbnW$AW3=oj1cUfyFcVw2TY2 zt~i!P*GNt~_6(^^CcJbpiuOQ*JjqHySith!$ zqs{rqXB`Bd_}e0hl*yBZpL?=sIu6p$9RN~D@IG}Y1H2$>EnJCPOBvk}r_68}vNS;J zsC;K-e1JGjlAeP;KlfQb+4u?4?bWcen5e-Z7GfVs&jBBlYa;4X7E|o%bnmwm({GFH zta&@>Qjdx1MVURLH*a6vV^CF1toS}=I*T2^IYT0@+ZsI1=Orl_qNXoiwj{hce;|h* zBgKy^nF#sKFx-F72)5w)Pv@@%b%hEoub?kClY~dk^N8SyF8`C)$kF